From 00c0d4e1778d0a1e90045e3067b5812c858b9451 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Sep 27 2022 20:17:01 +0000 Subject: import glibc-2.28-211.el8 --- diff --git a/SOURCES/SUPPORTED b/SOURCES/SUPPORTED index a4bf79c..fdf15fd 100644 --- a/SOURCES/SUPPORTED +++ b/SOURCES/SUPPORTED @@ -159,7 +159,8 @@ en_SG/ISO-8859-1 \ en_US.UTF-8/UTF-8 \ en_US/ISO-8859-1 \ en_US.ISO-8859-15/ISO-8859-15 \ -en_US@ampm.UTF-8/UTF-8 \ +en_US@ampm/UTF-8 \ +en_US.UTF-8@ampm/UTF-8 \ en_ZA.UTF-8/UTF-8 \ en_ZA/ISO-8859-1 \ en_ZM/UTF-8 \ diff --git a/SOURCES/build-locale-archive.c b/SOURCES/build-locale-archive.c index 9183972..3cb3b47 100644 --- a/SOURCES/build-locale-archive.c +++ b/SOURCES/build-locale-archive.c @@ -448,7 +448,7 @@ fill_archive (struct locarhandle *tmpl_ah, char fullname[fnamelen + 2 * strlen (d->d_name) + 7]; #ifdef _DIRENT_HAVE_D_TYPE - if (d_type == DT_UNKNOWN) + if (d_type == DT_UNKNOWN || d_type == DT_LNK) #endif { strcpy (stpcpy (stpcpy (fullname, fname), "/"), diff --git a/SOURCES/glibc-rh1888660.patch b/SOURCES/glibc-rh1888660.patch new file mode 100644 index 0000000..ec80b81 --- /dev/null +++ b/SOURCES/glibc-rh1888660.patch @@ -0,0 +1,767 @@ +This patch is a RHEL-8.7 backport of the following upstream commit: + +commit 52a103e237329b9f88a28513fe7506ffc3bd8ced +Author: Arjun Shankar +Date: Tue May 24 17:57:36 2022 +0200 + + Fix deadlock when pthread_atfork handler calls pthread_atfork or dlclose + + In multi-threaded programs, registering via pthread_atfork, + de-registering implicitly via dlclose, or running pthread_atfork + handlers during fork was protected by an internal lock. This meant + that a pthread_atfork handler attempting to register another handler or + dlclose a dynamically loaded library would lead to a deadlock. + + This commit fixes the deadlock in the following way: + + During the execution of handlers at fork time, the atfork lock is + released prior to the execution of each handler and taken again upon its + return. Any handler registrations or de-registrations that occurred + during the execution of the handler are accounted for before proceeding + with further handler execution. + + If a handler that hasn't been executed yet gets de-registered by another + handler during fork, it will not be executed. If a handler gets + registered by another handler during fork, it will not be executed + during that particular fork. + + The possibility that handlers may now be registered or deregistered + during handler execution means that identifying the next handler to be + run after a given handler may register/de-register others requires some + bookkeeping. The fork_handler struct has an additional field, 'id', + which is assigned sequentially during registration. Thus, handlers are + executed in ascending order of 'id' during 'prepare', and descending + order of 'id' during parent/child handler execution after the fork. + + Two tests are included: + + * tst-atfork3: Adhemerval Zanella + This test exercises calling dlclose from prepare, parent, and child + handlers. + + * tst-atfork4: This test exercises calling pthread_atfork and dlclose + from the prepare handler. + + [BZ #24595, BZ #27054] + + Co-authored-by: Adhemerval Zanella + Reviewed-by: Adhemerval Zanella + +diff --git a/nptl/Makefile b/nptl/Makefile +index 70a3be23ecfcd9c9..76c914e23e8873f2 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -382,8 +382,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \ + tst-cancelx16 tst-cancelx17 tst-cancelx18 tst-cancelx20 tst-cancelx21 \ + tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 + ifeq ($(build-shared),yes) +-tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder \ +- tst-audit-threads ++tests += \ ++ tst-atfork2 \ ++ tst-tls4 \ ++ tst-_res1 \ ++ tst-fini1 \ ++ tst-compat-forwarder \ ++ tst-audit-threads \ ++ tst-atfork3 \ ++ tst-atfork4 \ ++# tests ++ + tests-internal += tst-tls3 tst-tls3-malloc tst-tls5 tst-stackguard1 + tests-nolibpthread += tst-fini1 + ifeq ($(have-z-execstack),yes) +@@ -391,18 +400,39 @@ tests += tst-execstack + endif + endif + +-modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \ +- tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \ +- tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \ +- tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \ +- tst-join7mod tst-compat-forwarder-mod tst-audit-threads-mod1 \ +- tst-audit-threads-mod2 ++modules-names = \ ++ tst-atfork2mod \ ++ tst-tls3mod \ ++ tst-tls4moda \ ++ tst-tls4modb \ ++ tst-tls5mod \ ++ tst-tls5moda \ ++ tst-tls5modb \ ++ tst-tls5modc \ ++ tst-tls5modd \ ++ tst-tls5mode \ ++ tst-tls5modf \ ++ tst-stack4mod \ ++ tst-_res1mod1 \ ++ tst-_res1mod2 \ ++ tst-execstack-mod \ ++ tst-fini1mod \ ++ tst-join7mod \ ++ tst-compat-forwarder-mod \ ++ tst-audit-threads-mod1 \ ++ tst-audit-threads-mod2 \ ++ tst-atfork3mod \ ++ tst-atfork4mod \ ++# module-names ++ + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \ + tst-cleanup4aux.o tst-cleanupx4aux.o + test-extras += tst-cleanup4aux tst-cleanupx4aux + test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) + + tst-atfork2mod.so-no-z-defs = yes ++tst-atfork3mod.so-no-z-defs = yes ++tst-atfork4mod.so-no-z-defs = yes + tst-tls3mod.so-no-z-defs = yes + tst-tls5mod.so-no-z-defs = yes + tst-tls5moda.so-no-z-defs = yes +@@ -541,6 +571,14 @@ LDFLAGS-tst-atfork2 = -rdynamic + tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace + $(objpfx)tst-atfork2mod.so: $(shared-thread-library) + ++$(objpfx)tst-atfork3: $(libdl) $(shared-thread-library) ++LDFLAGS-tst-atfork3 = -rdynamic ++$(objpfx)tst-atfork3mod.so: $(shared-thread-library) ++ ++$(objpfx)tst-atfork4: $(libdl) $(shared-thread-library) ++LDFLAGS-tst-atfork4 = -rdynamic ++$(objpfx)tst-atfork4mod.so: $(shared-thread-library) ++ + tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace + $(objpfx)tst-stack3-mem.out: $(objpfx)tst-stack3.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@; \ +@@ -640,6 +678,8 @@ $(objpfx)../libc.so: $(common-objpfx)libc.so ; + $(addprefix $(objpfx),$(tests-static) $(xtests-static)): $(objpfx)libpthread.a + + $(objpfx)tst-atfork2.out: $(objpfx)tst-atfork2mod.so ++$(objpfx)tst-atfork3.out: $(objpfx)tst-atfork3mod.so ++$(objpfx)tst-atfork4.out: $(objpfx)tst-atfork4mod.so + else + $(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a + endif +diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c +index 9edb7d4bbb49fbed..4c1e20ae8cab005f 100644 +--- a/nptl/register-atfork.c ++++ b/nptl/register-atfork.c +@@ -21,6 +21,8 @@ + #include + #include + #include ++#include ++#include + + #define DYNARRAY_ELEMENT struct fork_handler + #define DYNARRAY_STRUCT fork_handler_list +@@ -29,7 +31,7 @@ + #include + + static struct fork_handler_list fork_handlers; +-static bool fork_handler_init = false; ++static uint64_t fork_handler_counter; + + static int atfork_lock = LLL_LOCK_INITIALIZER; + +@@ -39,11 +41,8 @@ __register_atfork (void (*prepare) (void), void (*parent) (void), + { + lll_lock (atfork_lock, LLL_PRIVATE); + +- if (!fork_handler_init) +- { +- fork_handler_list_init (&fork_handlers); +- fork_handler_init = true; +- } ++ if (fork_handler_counter == 0) ++ fork_handler_list_init (&fork_handlers); + + struct fork_handler *newp = fork_handler_list_emplace (&fork_handlers); + if (newp != NULL) +@@ -52,6 +51,13 @@ __register_atfork (void (*prepare) (void), void (*parent) (void), + newp->parent_handler = parent; + newp->child_handler = child; + newp->dso_handle = dso_handle; ++ ++ /* IDs assigned to handlers start at 1 and increment with handler ++ registration. Un-registering a handlers discards the corresponding ++ ID. It is not reused in future registrations. */ ++ if (INT_ADD_OVERFLOW (fork_handler_counter, 1)) ++ __libc_fatal ("fork handler counter overflow"); ++ newp->id = ++fork_handler_counter; + } + + /* Release the lock. */ +@@ -106,37 +112,111 @@ __unregister_atfork (void *dso_handle) + lll_unlock (atfork_lock, LLL_PRIVATE); + } + +-void +-__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking) ++uint64_t ++__run_prefork_handlers (_Bool do_locking) + { +- struct fork_handler *runp; ++ uint64_t lastrun; + +- if (who == atfork_run_prepare) ++ if (do_locking) ++ lll_lock (atfork_lock, LLL_PRIVATE); ++ ++ /* We run prepare handlers from last to first. After fork, only ++ handlers up to the last handler found here (pre-fork) will be run. ++ Handlers registered during __run_prefork_handlers or ++ __run_postfork_handlers will be positioned after this last handler, and ++ since their prepare handlers won't be run now, their parent/child ++ handlers should also be ignored. */ ++ lastrun = fork_handler_counter; ++ ++ size_t sl = fork_handler_list_size (&fork_handlers); ++ for (size_t i = sl; i > 0;) + { +- if (do_locking) +- lll_lock (atfork_lock, LLL_PRIVATE); +- size_t sl = fork_handler_list_size (&fork_handlers); +- for (size_t i = sl; i > 0; i--) +- { +- runp = fork_handler_list_at (&fork_handlers, i - 1); +- if (runp->prepare_handler != NULL) +- runp->prepare_handler (); +- } ++ struct fork_handler *runp ++ = fork_handler_list_at (&fork_handlers, i - 1); ++ ++ uint64_t id = runp->id; ++ ++ if (runp->prepare_handler != NULL) ++ { ++ if (do_locking) ++ lll_unlock (atfork_lock, LLL_PRIVATE); ++ ++ runp->prepare_handler (); ++ ++ if (do_locking) ++ lll_lock (atfork_lock, LLL_PRIVATE); ++ } ++ ++ /* We unlocked, ran the handler, and locked again. In the ++ meanwhile, one or more deregistrations could have occurred leading ++ to the current (just run) handler being moved up the list or even ++ removed from the list itself. Since handler IDs are guaranteed to ++ to be in increasing order, the next handler has to have: */ ++ ++ /* A. An earlier position than the current one has. */ ++ i--; ++ ++ /* B. A lower ID than the current one does. The code below skips ++ any newly added handlers with higher IDs. */ ++ while (i > 0 ++ && fork_handler_list_at (&fork_handlers, i - 1)->id >= id) ++ i--; + } +- else ++ ++ return lastrun; ++} ++ ++void ++__run_postfork_handlers (enum __run_fork_handler_type who, _Bool do_locking, ++ uint64_t lastrun) ++{ ++ size_t sl = fork_handler_list_size (&fork_handlers); ++ for (size_t i = 0; i < sl;) + { +- size_t sl = fork_handler_list_size (&fork_handlers); +- for (size_t i = 0; i < sl; i++) +- { +- runp = fork_handler_list_at (&fork_handlers, i); +- if (who == atfork_run_child && runp->child_handler) +- runp->child_handler (); +- else if (who == atfork_run_parent && runp->parent_handler) +- runp->parent_handler (); +- } ++ struct fork_handler *runp = fork_handler_list_at (&fork_handlers, i); ++ uint64_t id = runp->id; ++ ++ /* prepare handlers were not run for handlers with ID > LASTRUN. ++ Thus, parent/child handlers will also not be run. */ ++ if (id > lastrun) ++ break; ++ + if (do_locking) +- lll_unlock (atfork_lock, LLL_PRIVATE); ++ lll_unlock (atfork_lock, LLL_PRIVATE); ++ ++ if (who == atfork_run_child && runp->child_handler) ++ runp->child_handler (); ++ else if (who == atfork_run_parent && runp->parent_handler) ++ runp->parent_handler (); ++ ++ if (do_locking) ++ lll_lock (atfork_lock, LLL_PRIVATE); ++ ++ /* We unlocked, ran the handler, and locked again. In the meanwhile, ++ one or more [de]registrations could have occurred. Due to this, ++ the list size must be updated. */ ++ sl = fork_handler_list_size (&fork_handlers); ++ ++ /* The just-run handler could also have moved up the list. */ ++ ++ if (sl > i && fork_handler_list_at (&fork_handlers, i)->id == id) ++ /* The position of the recently run handler hasn't changed. The ++ next handler to be run is an easy increment away. */ ++ i++; ++ else ++ { ++ /* The next handler to be run is the first handler in the list ++ to have an ID higher than the current one. */ ++ for (i = 0; i < sl; i++) ++ { ++ if (fork_handler_list_at (&fork_handlers, i)->id > id) ++ break; ++ } ++ } + } ++ ++ if (do_locking) ++ lll_unlock (atfork_lock, LLL_PRIVATE); + } + + +diff --git a/nptl/tst-atfork3.c b/nptl/tst-atfork3.c +new file mode 100644 +index 0000000000000000..bb2250e432ab79ad +--- /dev/null ++++ b/nptl/tst-atfork3.c +@@ -0,0 +1,118 @@ ++/* Check if pthread_atfork handler can call dlclose (BZ#24595). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Check if pthread_atfork handlers do not deadlock when calling a function ++ that might alter the internal fork handle list, such as dlclose. ++ ++ The test registers a callback set with pthread_atfork(), dlopen() a shared ++ library (nptl/tst-atfork3mod.c), calls an exported symbol from the library ++ (which in turn also registers atfork handlers), and calls fork to trigger ++ the callbacks. */ ++ ++static void *handler; ++static bool run_dlclose_prepare; ++static bool run_dlclose_parent; ++static bool run_dlclose_child; ++ ++static void ++prepare (void) ++{ ++ if (run_dlclose_prepare) ++ xdlclose (handler); ++} ++ ++static void ++parent (void) ++{ ++ if (run_dlclose_parent) ++ xdlclose (handler); ++} ++ ++static void ++child (void) ++{ ++ if (run_dlclose_child) ++ xdlclose (handler); ++} ++ ++static void ++proc_func (void *closure) ++{ ++} ++ ++static void ++do_test_generic (bool dlclose_prepare, bool dlclose_parent, bool dlclose_child) ++{ ++ run_dlclose_prepare = dlclose_prepare; ++ run_dlclose_parent = dlclose_parent; ++ run_dlclose_child = dlclose_child; ++ ++ handler = xdlopen ("tst-atfork3mod.so", RTLD_NOW); ++ ++ int (*atfork3mod_func)(void); ++ atfork3mod_func = xdlsym (handler, "atfork3mod_func"); ++ ++ atfork3mod_func (); ++ ++ struct support_capture_subprocess proc ++ = support_capture_subprocess (proc_func, NULL); ++ support_capture_subprocess_check (&proc, "tst-atfork3", 0, sc_allow_none); ++ ++ handler = atfork3mod_func = NULL; ++ ++ support_capture_subprocess_free (&proc); ++} ++ ++static void * ++thread_func (void *closure) ++{ ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ { ++ /* Make the process acts as multithread. */ ++ pthread_attr_t attr; ++ xpthread_attr_init (&attr); ++ xpthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); ++ xpthread_create (&attr, thread_func, NULL); ++ } ++ ++ TEST_COMPARE (pthread_atfork (prepare, parent, child), 0); ++ ++ do_test_generic (true /* prepare */, false /* parent */, false /* child */); ++ do_test_generic (false /* prepare */, true /* parent */, false /* child */); ++ do_test_generic (false /* prepare */, false /* parent */, true /* child */); ++ ++ return 0; ++} ++ ++#include +diff --git a/nptl/tst-atfork3mod.c b/nptl/tst-atfork3mod.c +new file mode 100644 +index 0000000000000000..6d0658cb9efdecbc +--- /dev/null ++++ b/nptl/tst-atfork3mod.c +@@ -0,0 +1,44 @@ ++/* Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++ ++static void ++mod_prepare (void) ++{ ++} ++ ++static void ++mod_parent (void) ++{ ++} ++ ++static void ++mod_child (void) ++{ ++} ++ ++int atfork3mod_func (void) ++{ ++ TEST_COMPARE (pthread_atfork (mod_prepare, mod_parent, mod_child), 0); ++ ++ return 0; ++} +diff --git a/nptl/tst-atfork4.c b/nptl/tst-atfork4.c +new file mode 100644 +index 0000000000000000..52dc87e73b846ab9 +--- /dev/null ++++ b/nptl/tst-atfork4.c +@@ -0,0 +1,128 @@ ++/* pthread_atfork supports handlers that call pthread_atfork or dlclose. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void * ++thread_func (void *x) ++{ ++ return NULL; ++} ++ ++static unsigned int second_atfork_handler_runcount = 0; ++ ++static void ++second_atfork_handler (void) ++{ ++ second_atfork_handler_runcount++; ++} ++ ++static void *h = NULL; ++ ++static unsigned int atfork_handler_runcount = 0; ++ ++static void ++prepare (void) ++{ ++ /* These atfork handlers are registered while atfork handlers are being ++ executed and thus will not be executed during the corresponding ++ fork. */ ++ TEST_VERIFY_EXIT (pthread_atfork (second_atfork_handler, ++ second_atfork_handler, ++ second_atfork_handler) == 0); ++ ++ /* This will de-register the atfork handlers registered by the dlopen'd ++ library and so they will not be executed. */ ++ if (h != NULL) ++ { ++ xdlclose (h); ++ h = NULL; ++ } ++ ++ atfork_handler_runcount++; ++} ++ ++static void ++after (void) ++{ ++ atfork_handler_runcount++; ++} ++ ++static int ++do_test (void) ++{ ++ /* Make sure __libc_single_threaded is 0. */ ++ pthread_attr_t attr; ++ xpthread_attr_init (&attr); ++ xpthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); ++ xpthread_create (&attr, thread_func, NULL); ++ ++ void (*reg_atfork_handlers) (void); ++ ++ h = xdlopen ("tst-atfork4mod.so", RTLD_LAZY); ++ ++ reg_atfork_handlers = xdlsym (h, "reg_atfork_handlers"); ++ ++ reg_atfork_handlers (); ++ ++ /* We register our atfork handlers *after* loading the module so that our ++ prepare handler is called first at fork, where we then dlclose the ++ module before its prepare handler has a chance to be called. */ ++ TEST_VERIFY_EXIT (pthread_atfork (prepare, after, after) == 0); ++ ++ pid_t pid = xfork (); ++ ++ /* Both the parent and the child processes should observe this. */ ++ TEST_VERIFY_EXIT (atfork_handler_runcount == 2); ++ TEST_VERIFY_EXIT (second_atfork_handler_runcount == 0); ++ ++ if (pid > 0) ++ { ++ int childstat; ++ ++ xwaitpid (-1, &childstat, 0); ++ TEST_VERIFY_EXIT (WIFEXITED (childstat) ++ && WEXITSTATUS (childstat) == 0); ++ ++ /* This time, the second set of atfork handlers should also be called ++ since the handlers are already in place before fork is called. */ ++ ++ pid = xfork (); ++ ++ TEST_VERIFY_EXIT (atfork_handler_runcount == 4); ++ TEST_VERIFY_EXIT (second_atfork_handler_runcount == 2); ++ ++ if (pid > 0) ++ { ++ xwaitpid (-1, &childstat, 0); ++ TEST_VERIFY_EXIT (WIFEXITED (childstat) ++ && WEXITSTATUS (childstat) == 0); ++ } ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/nptl/tst-atfork4mod.c b/nptl/tst-atfork4mod.c +new file mode 100644 +index 0000000000000000..e111efeb185916e0 +--- /dev/null ++++ b/nptl/tst-atfork4mod.c +@@ -0,0 +1,48 @@ ++/* pthread_atfork supports handlers that call pthread_atfork or dlclose. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++/* This dynamically loaded library simply registers its atfork handlers when ++ asked to. The atfork handlers should never be executed because the ++ library is unloaded before fork is called by the test program. */ ++ ++static void ++prepare (void) ++{ ++ abort (); ++} ++ ++static void ++parent (void) ++{ ++ abort (); ++} ++ ++static void ++child (void) ++{ ++ abort (); ++} ++ ++void ++reg_atfork_handlers (void) ++{ ++ pthread_atfork (prepare, parent, child); ++} +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index b4d20fa652f4ba3b..1324b813136764fc 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -54,8 +54,9 @@ __libc_fork (void) + signal handlers. POSIX requires that fork is async-signal-safe, + but our current fork implementation is not. */ + bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads); ++ uint64_t lastrun; + +- __run_fork_handlers (atfork_run_prepare, multiple_threads); ++ lastrun = __run_prefork_handlers (multiple_threads); + + /* If we are not running multiple threads, we do not have to + preserve lock state. If fork runs from a signal handler, only +@@ -129,7 +130,7 @@ __libc_fork (void) + __rtld_lock_initialize (GL(dl_load_tls_lock)); + + /* Run the handlers registered for the child. */ +- __run_fork_handlers (atfork_run_child, multiple_threads); ++ __run_postfork_handlers (atfork_run_child, multiple_threads, lastrun); + } + else + { +@@ -144,7 +145,7 @@ __libc_fork (void) + } + + /* Run the handlers registered for the parent. */ +- __run_fork_handlers (atfork_run_parent, multiple_threads); ++ __run_postfork_handlers (atfork_run_parent, multiple_threads, lastrun); + } + + return pid; +diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h +index bef2b7a8a6af8635..222c4f618970a455 100644 +--- a/sysdeps/nptl/fork.h ++++ b/sysdeps/nptl/fork.h +@@ -31,6 +31,7 @@ struct fork_handler + void (*parent_handler) (void); + void (*child_handler) (void); + void *dso_handle; ++ uint64_t id; + }; + + /* Function to call to unregister fork handlers. */ +@@ -44,19 +45,18 @@ enum __run_fork_handler_type + atfork_run_parent + }; + +-/* Run the atfork handlers and lock/unlock the internal lock depending +- of the WHO argument: ++/* Run the atfork prepare handlers in the reverse order of registration and ++ return the ID of the last registered handler. If DO_LOCKING is true, the ++ internal lock is held locked upon return. */ ++extern uint64_t __run_prefork_handlers (_Bool do_locking) attribute_hidden; + +- - atfork_run_prepare: run all the PREPARE_HANDLER in reverse order of +- insertion and locks the internal lock. +- - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal +- lock. +- - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal +- lock. +- +- Perform locking only if DO_LOCKING. */ +-extern void __run_fork_handlers (enum __run_fork_handler_type who, +- _Bool do_locking) attribute_hidden; ++/* Given a handler type (parent or child), run all the atfork handlers in ++ the order of registration up to and including the handler with id equal ++ to LASTRUN. If DO_LOCKING is true, the internal lock is unlocked prior ++ to return. */ ++extern void __run_postfork_handlers (enum __run_fork_handler_type who, ++ _Bool do_locking, ++ uint64_t lastrun) attribute_hidden; + + /* C library side function to register new fork handlers. */ + extern int __register_atfork (void (*__prepare) (void), diff --git a/SOURCES/glibc-rh1961109.patch b/SOURCES/glibc-rh1961109.patch new file mode 100644 index 0000000..e47c4d7 --- /dev/null +++ b/SOURCES/glibc-rh1961109.patch @@ -0,0 +1,165 @@ +commit f17164bd51db31f47fbbdae826c63b6d78184c45 +Author: Florian Weimer +Date: Tue May 18 07:21:33 2021 +0200 + + localedata: Use U+00AF MACRON in more EBCDIC charsets [BZ #27882] + + This updates IBM256, IBM277, IBM278, IBM280, IBM284, IBM297, IBM424 + in the same way that IBM273 was updated for bug 23290. + + IBM256 and IBM424 still have holes after this change, so HAS_HOLES + is not updated. + + Reviewed-by: Siddhesh Poyarekar + +diff --git a/iconvdata/ibm277.c b/iconvdata/ibm277.c +index f93ca2acb8718dd5..0e337dbbdc06a02f 100644 +--- a/iconvdata/ibm277.c ++++ b/iconvdata/ibm277.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM277//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm278.c b/iconvdata/ibm278.c +index 4263000760472913..7450fb8e5b846101 100644 +--- a/iconvdata/ibm278.c ++++ b/iconvdata/ibm278.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM278//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm280.c b/iconvdata/ibm280.c +index 3efddd7dec2728d9..2ea5478e4e0d7007 100644 +--- a/iconvdata/ibm280.c ++++ b/iconvdata/ibm280.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM280//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm284.c b/iconvdata/ibm284.c +index 57dab27d0cec4a33..8dbbc6344d18528f 100644 +--- a/iconvdata/ibm284.c ++++ b/iconvdata/ibm284.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM284//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/iconvdata/ibm297.c b/iconvdata/ibm297.c +index f355659afd4b4502..81e63ba1f28f1548 100644 +--- a/iconvdata/ibm297.c ++++ b/iconvdata/ibm297.c +@@ -23,6 +23,6 @@ + #define TABLES + + #define CHARSET_NAME "IBM297//" +-#define HAS_HOLES 1 /* Not all 256 character are defined. */ ++#define HAS_HOLES 0 + + #include <8bit-gap.c> +diff --git a/localedata/charmaps/IBM256 b/localedata/charmaps/IBM256 +index 5cfd2db5f436cd07..bdc1abf0ade3bfc4 100644 +--- a/localedata/charmaps/IBM256 ++++ b/localedata/charmaps/IBM256 +@@ -194,7 +194,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf DOUBLE LOW LINE +diff --git a/localedata/charmaps/IBM277 b/localedata/charmaps/IBM277 +index 1c0b5cb9fb659364..2f6e3992109a2b33 100644 +--- a/localedata/charmaps/IBM277 ++++ b/localedata/charmaps/IBM277 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM278 b/localedata/charmaps/IBM278 +index 646961501c74c4df..bdfae7621028f003 100644 +--- a/localedata/charmaps/IBM278 ++++ b/localedata/charmaps/IBM278 +@@ -196,7 +196,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM280 b/localedata/charmaps/IBM280 +index 5de3b3e7b96796c0..4c31242806b0ac19 100644 +--- a/localedata/charmaps/IBM280 ++++ b/localedata/charmaps/IBM280 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM284 b/localedata/charmaps/IBM284 +index c64b2a65ab748540..46a8737a715e4e56 100644 +--- a/localedata/charmaps/IBM284 ++++ b/localedata/charmaps/IBM284 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba CIRCUMFLEX ACCENT + /xbb EXCLAMATION MARK +- /xbc OVERLINE ++ /xbc MACRON + /xbd TILDE + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM297 b/localedata/charmaps/IBM297 +index 33b74eee437241aa..14361ad418cf1bc7 100644 +--- a/localedata/charmaps/IBM297 ++++ b/localedata/charmaps/IBM297 +@@ -195,7 +195,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba NOT SIGN + /xbb VERTICAL LINE +- /xbc OVERLINE ++ /xbc MACRON + /xbd TILDE + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN +diff --git a/localedata/charmaps/IBM424 b/localedata/charmaps/IBM424 +index 883e43b8ae04ee4c..deca11e1b18ec0a6 100644 +--- a/localedata/charmaps/IBM424 ++++ b/localedata/charmaps/IBM424 +@@ -175,7 +175,7 @@ CHARMAP + /xb9 VULGAR FRACTION THREE QUARTERS + /xba LEFT SQUARE BRACKET + /xbb RIGHT SQUARE BRACKET +- /xbc OVERLINE ++ /xbc MACRON + /xbd DIAERESIS + /xbe ACUTE ACCENT + /xbf MULTIPLICATION SIGN diff --git a/SOURCES/glibc-rh1982608.patch b/SOURCES/glibc-rh1982608.patch new file mode 100644 index 0000000..6f67ed6 --- /dev/null +++ b/SOURCES/glibc-rh1982608.patch @@ -0,0 +1,2216 @@ +This is a rebase of posix/glob.c from upstream (gnulib->glibc->rhel). + +Relevent upstream commits: + +7c477b57a31487eda516db02b9e04f22d1a6e6af posix/glob.c: update from gnulib + (This is the master commit to which we're syncing) + +gnulib commit 98f034a0c2ba8917c96f363de1a8d66244e411da + (This is the gnulib commit to which glibc upstream sync'd) + +Additional glibc upstream commits of note: +84f7ce84474c1648ce96884f1c91ca7b97ca3fc2 posix: Add glob64 with 64-bit time_t support + (just posix/glob.c and sysdeps/gnu/glob64-lstat-compat.c) +9a7ab0769b295cbf5232140401742a8f34bda3de hurd: Fix glob lstat compatibility +4883360415f1ed772ba44decc501d59deb17bdf0 posix: Sync glob code with gnulib +04986243d1af37ac0177ed2f9db0a066ebd2b212 Remove internal usage of extensible stat functions +ddc650e9b3dc916eab417ce9f79e67337b05035c Fix use-after-free in glob when expanding ~user (bug 25414) + + +diff -rup a/posix/glob-lstat-compat.c b/posix/glob-lstat-compat.c +--- a/posix/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/posix/glob-lstat-compat.c 2022-05-02 22:49:06.504676711 -0400 +@@ -28,7 +28,8 @@ + # define GLOB_ATTRIBUTE attribute_compat_text_section + + /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */ +-# define GLOB_NO_LSTAT ++# define GLOB_LSTAT gl_stat ++# define GLOB_LSTAT64 __stat64 + + # include + +diff -rup a/posix/glob.c b/posix/glob.c +--- a/posix/glob.c 2022-05-03 14:37:52.959042051 -0400 ++++ b/posix/glob.c 2022-05-02 22:49:18.655134696 -0400 +@@ -1,4 +1,4 @@ +-/* Copyright (C) 1991-2018 Free Software Foundation, Inc. ++/* Copyright (C) 1991-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -13,11 +13,22 @@ + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see +- . */ ++ . */ ++ ++#ifndef _LIBC ++ ++/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc ++ optimizes away the pattern == NULL test below. */ ++# define _GL_ARG_NONNULL(params) ++ ++# include ++ ++#endif + + #include + + #include ++#include + #include + #include + #include +@@ -26,7 +37,7 @@ + #include + #include + +-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ ++#if defined _WIN32 && ! defined __CYGWIN__ + # define WINDOWS32 + #endif + +@@ -46,30 +57,38 @@ + # define sysconf(id) __sysconf (id) + # define closedir(dir) __closedir (dir) + # define opendir(name) __opendir (name) ++# undef dirfd ++# define dirfd(str) __dirfd (str) + # define readdir(str) __readdir64 (str) + # define getpwnam_r(name, bufp, buf, len, res) \ + __getpwnam_r (name, bufp, buf, len, res) +-# ifndef __lstat64 +-# define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) ++# define FLEXIBLE_ARRAY_MEMBER ++# ifndef struct_stat ++# define struct_stat struct stat + # endif +-# ifndef __stat64 +-# define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) ++# ifndef struct_stat64 ++# define struct_stat64 struct stat64 ++# endif ++# ifndef GLOB_LSTAT ++# define GLOB_LSTAT gl_lstat ++# endif ++# ifndef GLOB_FSTATAT64 ++# define GLOB_FSTATAT64 __fstatat64 + # endif +-# define struct_stat64 struct stat64 +-# define FLEXIBLE_ARRAY_MEMBER + # include + #else /* !_LIBC */ + # define __glob glob + # define __getlogin_r(buf, len) getlogin_r (buf, len) +-# define __lstat64(fname, buf) lstat (fname, buf) +-# define __stat64(fname, buf) stat (fname, buf) + # define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag) +-# define struct_stat64 struct stat + # ifndef __MVS__ + # define __alloca alloca + # endif + # define __readdir readdir + # define COMPILE_GLOB64 ++# define struct_stat struct stat ++# define struct_stat64 struct stat ++# define GLOB_LSTAT gl_lstat ++# define GLOB_FSTATAT64 fstatat + #endif /* _LIBC */ + + #include +@@ -80,7 +99,9 @@ + + static const char *next_brace_sub (const char *begin, int flags) __THROWNL; + +-typedef uint_fast8_t dirent_type; ++/* The type of ((struct dirent *) 0)->d_type is 'unsigned char' on most ++ platforms, but 'unsigned int' in the mingw from mingw.org. */ ++typedef uint_fast32_t dirent_type; + + #if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE + /* Any distinct values will do here. +@@ -119,9 +140,9 @@ readdir_result_type (struct readdir_resu + /* Construct an initializer for a struct readdir_result object from a + struct dirent *. No copy of the name is made. */ + #define READDIR_RESULT_INITIALIZER(source) \ +- { \ +- source->d_name, \ +- D_TYPE_TO_RESULT (source) \ ++ { \ ++ source->d_name, \ ++ D_TYPE_TO_RESULT (source) \ + } + + /* Call gl_readdir on STREAM. This macro can be overridden to reduce +@@ -186,22 +207,15 @@ glob_lstat (glob_t *pglob, int flags, co + { + /* Use on glob-lstat-compat.c to provide a compat symbol which does not + use lstat / gl_lstat. */ +-#ifdef GLOB_NO_LSTAT +-# define GL_LSTAT gl_stat +-# define LSTAT64 __stat64 +-#else +-# define GL_LSTAT gl_lstat +-# define LSTAT64 __lstat64 +-#endif +- + union + { +- struct stat st; ++ struct_stat st; + struct_stat64 st64; + } ust; + return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC) +- ? pglob->GL_LSTAT (fullname, &ust.st) +- : LSTAT64 (fullname, &ust.st64)); ++ ? pglob->GLOB_LSTAT (fullname, &ust.st) ++ : GLOB_FSTATAT64 (AT_FDCWD, fullname, &ust.st64, ++ AT_SYMLINK_NOFOLLOW)); + } + + /* Set *R = A + B. Return true if the answer is mathematically +@@ -211,7 +225,7 @@ glob_lstat (glob_t *pglob, int flags, co + static bool + size_add_wrapv (size_t a, size_t b, size_t *r) + { +-#if 5 <= __GNUC__ && !defined __ICC ++#if 7 <= __GNUC__ && !defined __ICC + return __builtin_add_overflow (a, b, r); + #else + *r = a + b; +@@ -228,8 +242,8 @@ glob_use_alloca (size_t alloca_used, siz + } + + static int glob_in_dir (const char *pattern, const char *directory, +- int flags, int (*errfunc) (const char *, int), +- glob_t *pglob, size_t alloca_used); ++ int flags, int (*errfunc) (const char *, int), ++ glob_t *pglob, size_t alloca_used); + static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL; + static int collated_compare (const void *, const void *) __THROWNL; + +@@ -239,11 +253,12 @@ static int collated_compare (const void + static bool + is_dir (char const *filename, int flags, glob_t const *pglob) + { +- struct stat st; ++ struct_stat st; + struct_stat64 st64; + return (__glibc_unlikely (flags & GLOB_ALTDIRFUNC) + ? pglob->gl_stat (filename, &st) == 0 && S_ISDIR (st.st_mode) +- : __stat64 (filename, &st64) == 0 && S_ISDIR (st64.st_mode)); ++ : (GLOB_FSTATAT64 (AT_FDCWD, filename, &st64, 0) == 0 ++ && S_ISDIR (st64.st_mode))); + } + + /* Find the end of the sub-pattern in a brace expression. */ +@@ -254,17 +269,17 @@ next_brace_sub (const char *cp, int flag + while (*cp != '\0') + if ((flags & GLOB_NOESCAPE) == 0 && *cp == '\\') + { +- if (*++cp == '\0') +- break; +- ++cp; ++ if (*++cp == '\0') ++ break; ++ ++cp; + } + else + { +- if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) +- break; ++ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) ++ break; + +- if (*cp++ == '{') +- depth++; ++ if (*cp++ == '{') ++ depth++; + } + + return *cp != '\0' ? cp : NULL; +@@ -285,7 +300,7 @@ next_brace_sub (const char *cp, int flag + int + GLOB_ATTRIBUTE + __glob (const char *pattern, int flags, int (*errfunc) (const char *, int), +- glob_t *pglob) ++ glob_t *pglob) + { + const char *filename; + char *dirname = NULL; +@@ -319,22 +334,22 @@ __glob (const char *pattern, int flags, + { + pglob->gl_pathc = 0; + if (!(flags & GLOB_DOOFFS)) +- pglob->gl_pathv = NULL; ++ pglob->gl_pathv = NULL; + else +- { +- size_t i; ++ { ++ size_t i; + +- if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) +- return GLOB_NOSPACE; ++ if (pglob->gl_offs >= ~((size_t) 0) / sizeof (char *)) ++ return GLOB_NOSPACE; + +- pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) +- * sizeof (char *)); +- if (pglob->gl_pathv == NULL) +- return GLOB_NOSPACE; +- +- for (i = 0; i <= pglob->gl_offs; ++i) +- pglob->gl_pathv[i] = NULL; +- } ++ pglob->gl_pathv = (char **) malloc ((pglob->gl_offs + 1) ++ * sizeof (char *)); ++ if (pglob->gl_pathv == NULL) ++ return GLOB_NOSPACE; ++ ++ for (i = 0; i <= pglob->gl_offs; ++i) ++ pglob->gl_pathv[i] = NULL; ++ } + } + + if (flags & GLOB_BRACE) +@@ -342,129 +357,129 @@ __glob (const char *pattern, int flags, + const char *begin; + + if (flags & GLOB_NOESCAPE) +- begin = strchr (pattern, '{'); ++ begin = strchr (pattern, '{'); + else +- { +- begin = pattern; +- while (1) +- { +- if (*begin == '\0') +- { +- begin = NULL; +- break; +- } +- +- if (*begin == '\\' && begin[1] != '\0') +- ++begin; +- else if (*begin == '{') +- break; +- +- ++begin; +- } +- } ++ { ++ begin = pattern; ++ while (1) ++ { ++ if (*begin == '\0') ++ { ++ begin = NULL; ++ break; ++ } ++ ++ if (*begin == '\\' && begin[1] != '\0') ++ ++begin; ++ else if (*begin == '{') ++ break; ++ ++ ++begin; ++ } ++ } + + if (begin != NULL) +- { +- /* Allocate working buffer large enough for our work. Note that +- we have at least an opening and closing brace. */ +- size_t firstc; +- char *alt_start; +- const char *p; +- const char *next; +- const char *rest; +- size_t rest_len; +- char *onealt; +- size_t pattern_len = strlen (pattern) - 1; +- int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); +- if (alloca_onealt) +- onealt = alloca_account (pattern_len, alloca_used); +- else +- { +- onealt = malloc (pattern_len); +- if (onealt == NULL) +- return GLOB_NOSPACE; +- } +- +- /* We know the prefix for all sub-patterns. */ +- alt_start = mempcpy (onealt, pattern, begin - pattern); +- +- /* Find the first sub-pattern and at the same time find the +- rest after the closing brace. */ +- next = next_brace_sub (begin + 1, flags); +- if (next == NULL) +- { +- /* It is an invalid expression. */ +- illegal_brace: +- if (__glibc_unlikely (!alloca_onealt)) +- free (onealt); +- flags &= ~GLOB_BRACE; +- goto no_brace; +- } +- +- /* Now find the end of the whole brace expression. */ +- rest = next; +- while (*rest != '}') +- { +- rest = next_brace_sub (rest + 1, flags); +- if (rest == NULL) +- /* It is an illegal expression. */ +- goto illegal_brace; +- } +- /* Please note that we now can be sure the brace expression +- is well-formed. */ +- rest_len = strlen (++rest) + 1; +- +- /* We have a brace expression. BEGIN points to the opening {, +- NEXT points past the terminator of the first element, and END +- points past the final }. We will accumulate result names from +- recursive runs for each brace alternative in the buffer using +- GLOB_APPEND. */ +- firstc = pglob->gl_pathc; +- +- p = begin + 1; +- while (1) +- { +- int result; +- +- /* Construct the new glob expression. */ +- mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); +- +- result = __glob (onealt, +- ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) +- | GLOB_APPEND), +- errfunc, pglob); +- +- /* If we got an error, return it. */ +- if (result && result != GLOB_NOMATCH) +- { +- if (__glibc_unlikely (!alloca_onealt)) +- free (onealt); +- if (!(flags & GLOB_APPEND)) +- { +- globfree (pglob); +- pglob->gl_pathc = 0; +- } +- return result; +- } +- +- if (*next == '}') +- /* We saw the last entry. */ +- break; +- +- p = next + 1; +- next = next_brace_sub (p, flags); +- assert (next != NULL); +- } +- +- if (__glibc_unlikely (!alloca_onealt)) +- free (onealt); +- +- if (pglob->gl_pathc != firstc) +- /* We found some entries. */ +- return 0; +- else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) +- return GLOB_NOMATCH; +- } ++ { ++ /* Allocate working buffer large enough for our work. Note that ++ we have at least an opening and closing brace. */ ++ size_t firstc; ++ char *alt_start; ++ const char *p; ++ const char *next; ++ const char *rest; ++ size_t rest_len; ++ char *onealt; ++ size_t pattern_len = strlen (pattern) - 1; ++ int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); ++ if (alloca_onealt) ++ onealt = alloca_account (pattern_len, alloca_used); ++ else ++ { ++ onealt = malloc (pattern_len); ++ if (onealt == NULL) ++ return GLOB_NOSPACE; ++ } ++ ++ /* We know the prefix for all sub-patterns. */ ++ alt_start = mempcpy (onealt, pattern, begin - pattern); ++ ++ /* Find the first sub-pattern and at the same time find the ++ rest after the closing brace. */ ++ next = next_brace_sub (begin + 1, flags); ++ if (next == NULL) ++ { ++ /* It is an invalid expression. */ ++ illegal_brace: ++ if (__glibc_unlikely (!alloca_onealt)) ++ free (onealt); ++ flags &= ~GLOB_BRACE; ++ goto no_brace; ++ } ++ ++ /* Now find the end of the whole brace expression. */ ++ rest = next; ++ while (*rest != '}') ++ { ++ rest = next_brace_sub (rest + 1, flags); ++ if (rest == NULL) ++ /* It is an illegal expression. */ ++ goto illegal_brace; ++ } ++ /* Please note that we now can be sure the brace expression ++ is well-formed. */ ++ rest_len = strlen (++rest) + 1; ++ ++ /* We have a brace expression. BEGIN points to the opening {, ++ NEXT points past the terminator of the first element, and END ++ points past the final }. We will accumulate result names from ++ recursive runs for each brace alternative in the buffer using ++ GLOB_APPEND. */ ++ firstc = pglob->gl_pathc; ++ ++ p = begin + 1; ++ while (1) ++ { ++ int result; ++ ++ /* Construct the new glob expression. */ ++ mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); ++ ++ result = __glob (onealt, ++ ((flags & ~(GLOB_NOCHECK | GLOB_NOMAGIC)) ++ | GLOB_APPEND), ++ errfunc, pglob); ++ ++ /* If we got an error, return it. */ ++ if (result && result != GLOB_NOMATCH) ++ { ++ if (__glibc_unlikely (!alloca_onealt)) ++ free (onealt); ++ if (!(flags & GLOB_APPEND)) ++ { ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ } ++ return result; ++ } ++ ++ if (*next == '}') ++ /* We saw the last entry. */ ++ break; ++ ++ p = next + 1; ++ next = next_brace_sub (p, flags); ++ assert (next != NULL); ++ } ++ ++ if (__glibc_unlikely (!alloca_onealt)) ++ free (onealt); ++ ++ if (pglob->gl_pathc != firstc) ++ /* We found some entries. */ ++ return 0; ++ else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) ++ return GLOB_NOMATCH; ++ } + } + + no_brace: +@@ -486,33 +501,33 @@ __glob (const char *pattern, int flags, + if (filename == NULL) + { + /* This can mean two things: a simple name or "~name". The latter +- case is nothing but a notation for a directory. */ ++ case is nothing but a notation for a directory. */ + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~') +- { +- dirname = (char *) pattern; +- dirlen = strlen (pattern); +- +- /* Set FILENAME to NULL as a special flag. This is ugly but +- other solutions would require much more code. We test for +- this special case below. */ +- filename = NULL; +- } ++ { ++ dirname = (char *) pattern; ++ dirlen = strlen (pattern); ++ ++ /* Set FILENAME to NULL as a special flag. This is ugly but ++ other solutions would require much more code. We test for ++ this special case below. */ ++ filename = NULL; ++ } + else +- { +- if (__glibc_unlikely (pattern[0] == '\0')) +- { +- dirs.gl_pathv = NULL; +- goto no_matches; +- } +- +- filename = pattern; +- dirname = (char *) "."; +- dirlen = 0; +- } ++ { ++ if (__glibc_unlikely (pattern[0] == '\0')) ++ { ++ dirs.gl_pathv = NULL; ++ goto no_matches; ++ } ++ ++ filename = pattern; ++ dirname = (char *) "."; ++ dirlen = 0; ++ } + } + else if (filename == pattern +- || (filename == pattern + 1 && pattern[0] == '\\' +- && (flags & GLOB_NOESCAPE) == 0)) ++ || (filename == pattern + 1 && pattern[0] == '\\' ++ && (flags & GLOB_NOESCAPE) == 0)) + { + /* "/pattern" or "\\/pattern". */ + dirname = (char *) "/"; +@@ -525,32 +540,32 @@ __glob (const char *pattern, int flags, + dirlen = filename - pattern; + #if defined __MSDOS__ || defined WINDOWS32 + if (*filename == ':' +- || (filename > pattern + 1 && filename[-1] == ':')) +- { +- char *drive_spec; +- +- ++dirlen; +- drive_spec = __alloca (dirlen + 1); +- *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; +- /* For now, disallow wildcards in the drive spec, to +- prevent infinite recursion in glob. */ +- if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) +- return GLOB_NOMATCH; +- /* If this is "d:pattern", we need to copy ':' to DIRNAME +- as well. If it's "d:/pattern", don't remove the slash +- from "d:/", since "d:" and "d:/" are not the same.*/ +- } ++ || (filename > pattern + 1 && filename[-1] == ':')) ++ { ++ char *drive_spec; ++ ++ ++dirlen; ++ drive_spec = __alloca (dirlen + 1); ++ *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; ++ /* For now, disallow wildcards in the drive spec, to ++ prevent infinite recursion in glob. */ ++ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) ++ return GLOB_NOMATCH; ++ /* If this is "d:pattern", we need to copy ':' to DIRNAME ++ as well. If it's "d:/pattern", don't remove the slash ++ from "d:/", since "d:" and "d:/" are not the same.*/ ++ } + #endif + + if (glob_use_alloca (alloca_used, dirlen + 1)) +- newp = alloca_account (dirlen + 1, alloca_used); ++ newp = alloca_account (dirlen + 1, alloca_used); + else +- { +- newp = malloc (dirlen + 1); +- if (newp == NULL) +- return GLOB_NOSPACE; +- malloc_dirname = 1; +- } ++ { ++ newp = malloc (dirlen + 1); ++ if (newp == NULL) ++ return GLOB_NOSPACE; ++ malloc_dirname = 1; ++ } + *((char *) mempcpy (newp, pattern, dirlen)) = '\0'; + dirname = newp; + ++filename; +@@ -566,363 +581,383 @@ __glob (const char *pattern, int flags, + + if (filename[0] == '\0' && dirlen > 1 && !drive_root) + /* "pattern/". Expand "pattern", appending slashes. */ +- { +- int orig_flags = flags; +- if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') +- { +- /* "pattern\\/". Remove the final backslash if it hasn't +- been quoted. */ +- char *p = (char *) &dirname[dirlen - 1]; +- +- while (p > dirname && p[-1] == '\\') --p; +- if ((&dirname[dirlen] - p) & 1) +- { +- *(char *) &dirname[--dirlen] = '\0'; +- flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); +- } +- } +- int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob); +- if (val == 0) +- pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) +- | (flags & GLOB_MARK)); +- else if (val == GLOB_NOMATCH && flags != orig_flags) +- { +- /* Make sure globfree (&dirs); is a nop. */ +- dirs.gl_pathv = NULL; +- flags = orig_flags; +- oldcount = pglob->gl_pathc + pglob->gl_offs; +- goto no_matches; +- } +- retval = val; +- goto out; +- } ++ { ++ int orig_flags = flags; ++ if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') ++ { ++ /* "pattern\\/". Remove the final backslash if it hasn't ++ been quoted. */ ++ char *p = (char *) &dirname[dirlen - 1]; ++ ++ while (p > dirname && p[-1] == '\\') --p; ++ if ((&dirname[dirlen] - p) & 1) ++ { ++ *(char *) &dirname[--dirlen] = '\0'; ++ flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); ++ } ++ } ++ int val = __glob (dirname, flags | GLOB_MARK, errfunc, pglob); ++ if (val == 0) ++ pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) ++ | (flags & GLOB_MARK)); ++ else if (val == GLOB_NOMATCH && flags != orig_flags) ++ { ++ /* Make sure globfree (&dirs); is a nop. */ ++ dirs.gl_pathv = NULL; ++ flags = orig_flags; ++ oldcount = pglob->gl_pathc + pglob->gl_offs; ++ goto no_matches; ++ } ++ retval = val; ++ goto out; ++ } + } + + if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') + { + if (dirname[1] == '\0' || dirname[1] == '/' +- || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' +- && (dirname[2] == '\0' || dirname[2] == '/'))) +- { +- /* Look up home directory. */ +- char *home_dir = getenv ("HOME"); +- int malloc_home_dir = 0; +- if (home_dir == NULL || home_dir[0] == '\0') +- { ++ || (!(flags & GLOB_NOESCAPE) && dirname[1] == '\\' ++ && (dirname[2] == '\0' || dirname[2] == '/'))) ++ { ++ /* Look up home directory. */ ++ char *home_dir = getenv ("HOME"); ++ int malloc_home_dir = 0; ++ if (home_dir == NULL || home_dir[0] == '\0') ++ { + #ifdef WINDOWS32 +- /* Windows NT defines HOMEDRIVE and HOMEPATH. But give +- preference to HOME, because the user can change HOME. */ +- const char *home_drive = getenv ("HOMEDRIVE"); +- const char *home_path = getenv ("HOMEPATH"); +- +- if (home_drive != NULL && home_path != NULL) +- { +- size_t home_drive_len = strlen (home_drive); +- size_t home_path_len = strlen (home_path); +- char *mem = alloca (home_drive_len + home_path_len + 1); +- +- memcpy (mem, home_drive, home_drive_len); +- memcpy (mem + home_drive_len, home_path, home_path_len + 1); +- home_dir = mem; +- } +- else +- home_dir = "c:/users/default"; /* poor default */ ++ /* Windows NT defines HOMEDRIVE and HOMEPATH. But give ++ preference to HOME, because the user can change HOME. */ ++ const char *home_drive = getenv ("HOMEDRIVE"); ++ const char *home_path = getenv ("HOMEPATH"); ++ ++ if (home_drive != NULL && home_path != NULL) ++ { ++ size_t home_drive_len = strlen (home_drive); ++ size_t home_path_len = strlen (home_path); ++ char *mem = alloca (home_drive_len + home_path_len + 1); ++ ++ memcpy (mem, home_drive, home_drive_len); ++ memcpy (mem + home_drive_len, home_path, home_path_len + 1); ++ home_dir = mem; ++ } ++ else ++ home_dir = "c:/users/default"; /* poor default */ + #else +- int err; +- struct passwd *p; +- struct passwd pwbuf; +- struct scratch_buffer s; +- scratch_buffer_init (&s); +- while (true) +- { +- p = NULL; +- err = __getlogin_r (s.data, s.length); +- if (err == 0) +- { ++ int err; ++ struct passwd *p; ++ struct passwd pwbuf; ++ struct scratch_buffer s; ++ scratch_buffer_init (&s); ++ while (true) ++ { ++ p = NULL; ++ err = __getlogin_r (s.data, s.length); ++ if (err == 0) ++ { + # if defined HAVE_GETPWNAM_R || defined _LIBC +- size_t ssize = strlen (s.data) + 1; +- char *sdata = s.data; +- err = getpwnam_r (sdata, &pwbuf, sdata + ssize, +- s.length - ssize, &p); ++ size_t ssize = strlen (s.data) + 1; ++ char *sdata = s.data; ++ err = getpwnam_r (sdata, &pwbuf, sdata + ssize, ++ s.length - ssize, &p); + # else +- p = getpwnam (s.data); +- if (p == NULL) +- err = errno; ++ p = getpwnam (s.data); ++ if (p == NULL) ++ err = errno; + # endif +- } +- if (err != ERANGE) +- break; +- if (!scratch_buffer_grow (&s)) +- { +- retval = GLOB_NOSPACE; +- goto out; +- } +- } +- if (err == 0) +- { +- home_dir = strdup (p->pw_dir); +- malloc_home_dir = 1; +- } +- scratch_buffer_free (&s); +- if (err == 0 && home_dir == NULL) +- { +- retval = GLOB_NOSPACE; +- goto out; +- } ++ } ++ if (err != ERANGE) ++ break; ++ if (!scratch_buffer_grow (&s)) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } ++ if (err == 0) ++ { ++ home_dir = strdup (p->pw_dir); ++ malloc_home_dir = 1; ++ } ++ scratch_buffer_free (&s); ++ if (err == 0 && home_dir == NULL) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } + #endif /* WINDOWS32 */ +- } +- if (home_dir == NULL || home_dir[0] == '\0') +- { +- if (__glibc_unlikely (malloc_home_dir)) +- free (home_dir); +- if (flags & GLOB_TILDE_CHECK) +- { +- retval = GLOB_NOMATCH; +- goto out; +- } +- else +- { +- home_dir = (char *) "~"; /* No luck. */ +- malloc_home_dir = 0; +- } +- } +- /* Now construct the full directory. */ +- if (dirname[1] == '\0') +- { +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- +- dirname = home_dir; +- dirlen = strlen (dirname); +- malloc_dirname = malloc_home_dir; +- } +- else +- { +- char *newp; +- size_t home_len = strlen (home_dir); +- int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); +- if (use_alloca) +- newp = alloca_account (home_len + dirlen, alloca_used); +- else +- { +- newp = malloc (home_len + dirlen); +- if (newp == NULL) +- { +- if (__glibc_unlikely (malloc_home_dir)) +- free (home_dir); +- retval = GLOB_NOSPACE; +- goto out; +- } +- } +- +- mempcpy (mempcpy (newp, home_dir, home_len), +- &dirname[1], dirlen); +- +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- +- dirname = newp; +- dirlen += home_len - 1; +- malloc_dirname = !use_alloca; +- +- if (__glibc_unlikely (malloc_home_dir)) +- free (home_dir); +- } +- dirname_modified = 1; +- } ++ } ++ if (home_dir == NULL || home_dir[0] == '\0') ++ { ++ if (__glibc_unlikely (malloc_home_dir)) ++ free (home_dir); ++ if (flags & GLOB_TILDE_CHECK) ++ { ++ retval = GLOB_NOMATCH; ++ goto out; ++ } ++ else ++ { ++ home_dir = (char *) "~"; /* No luck. */ ++ malloc_home_dir = 0; ++ } ++ } ++ /* Now construct the full directory. */ ++ if (dirname[1] == '\0') ++ { ++ if (__glibc_unlikely (malloc_dirname)) ++ free (dirname); ++ ++ dirname = home_dir; ++ dirlen = strlen (dirname); ++ malloc_dirname = malloc_home_dir; ++ } ++ else ++ { ++ char *newp; ++ size_t home_len = strlen (home_dir); ++ int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); ++ if (use_alloca) ++ newp = alloca_account (home_len + dirlen, alloca_used); ++ else ++ { ++ newp = malloc (home_len + dirlen); ++ if (newp == NULL) ++ { ++ if (__glibc_unlikely (malloc_home_dir)) ++ free (home_dir); ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } ++ ++ mempcpy (mempcpy (newp, home_dir, home_len), ++ &dirname[1], dirlen); ++ ++ if (__glibc_unlikely (malloc_dirname)) ++ free (dirname); ++ ++ dirname = newp; ++ dirlen += home_len - 1; ++ malloc_dirname = !use_alloca; ++ ++ if (__glibc_unlikely (malloc_home_dir)) ++ free (home_dir); ++ } ++ dirname_modified = 1; ++ } + else +- { ++ { + #ifndef WINDOWS32 +- char *end_name = strchr (dirname, '/'); +- char *user_name; +- int malloc_user_name = 0; +- char *unescape = NULL; +- +- if (!(flags & GLOB_NOESCAPE)) +- { +- if (end_name == NULL) +- { +- unescape = strchr (dirname, '\\'); +- if (unescape) +- end_name = strchr (unescape, '\0'); +- } +- else +- unescape = memchr (dirname, '\\', end_name - dirname); +- } +- if (end_name == NULL) +- user_name = dirname + 1; +- else +- { +- char *newp; +- if (glob_use_alloca (alloca_used, end_name - dirname)) +- newp = alloca_account (end_name - dirname, alloca_used); +- else +- { +- newp = malloc (end_name - dirname); +- if (newp == NULL) +- { +- retval = GLOB_NOSPACE; +- goto out; +- } +- malloc_user_name = 1; +- } +- if (unescape != NULL) +- { +- char *p = mempcpy (newp, dirname + 1, +- unescape - dirname - 1); +- char *q = unescape; +- while (q != end_name) +- { +- if (*q == '\\') +- { +- if (q + 1 == end_name) +- { +- /* "~fo\\o\\" unescape to user_name "foo\\", +- but "~fo\\o\\/" unescape to user_name +- "foo". */ +- if (filename == NULL) +- *p++ = '\\'; +- break; +- } +- ++q; +- } +- *p++ = *q++; +- } +- *p = '\0'; +- } +- else +- *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) +- = '\0'; +- user_name = newp; +- } +- +- /* Look up specific user's home directory. */ +- { +- struct passwd *p; +- struct scratch_buffer pwtmpbuf; +- scratch_buffer_init (&pwtmpbuf); ++ /* Recognize ~user as a shorthand for the specified user's home ++ directory. */ ++ char *end_name = strchr (dirname, '/'); ++ char *user_name; ++ int malloc_user_name = 0; ++ char *unescape = NULL; ++ ++ if (!(flags & GLOB_NOESCAPE)) ++ { ++ if (end_name == NULL) ++ { ++ unescape = strchr (dirname, '\\'); ++ if (unescape) ++ end_name = strchr (unescape, '\0'); ++ } ++ else ++ unescape = memchr (dirname, '\\', end_name - dirname); ++ } ++ if (end_name == NULL) ++ user_name = dirname + 1; ++ else ++ { ++ char *newp; ++ if (glob_use_alloca (alloca_used, end_name - dirname)) ++ newp = alloca_account (end_name - dirname, alloca_used); ++ else ++ { ++ newp = malloc (end_name - dirname); ++ if (newp == NULL) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ malloc_user_name = 1; ++ } ++ if (unescape != NULL) ++ { ++ char *p = mempcpy (newp, dirname + 1, ++ unescape - dirname - 1); ++ char *q = unescape; ++ while (q != end_name) ++ { ++ if (*q == '\\') ++ { ++ if (q + 1 == end_name) ++ { ++ /* "~fo\\o\\" unescape to user_name "foo\\", ++ but "~fo\\o\\/" unescape to user_name ++ "foo". */ ++ if (filename == NULL) ++ *p++ = '\\'; ++ break; ++ } ++ ++q; ++ } ++ *p++ = *q++; ++ } ++ *p = '\0'; ++ } ++ else ++ *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) ++ = '\0'; ++ user_name = newp; ++ } ++ ++ /* Look up specific user's home directory. */ ++ { ++ struct passwd *p; ++ struct scratch_buffer pwtmpbuf; ++ scratch_buffer_init (&pwtmpbuf); + + # if defined HAVE_GETPWNAM_R || defined _LIBC +- struct passwd pwbuf; ++ struct passwd pwbuf; + +- while (getpwnam_r (user_name, &pwbuf, +- pwtmpbuf.data, pwtmpbuf.length, &p) +- == ERANGE) +- { +- if (!scratch_buffer_grow (&pwtmpbuf)) +- { +- retval = GLOB_NOSPACE; +- goto out; +- } +- } ++ while (getpwnam_r (user_name, &pwbuf, ++ pwtmpbuf.data, pwtmpbuf.length, &p) ++ == ERANGE) ++ { ++ if (!scratch_buffer_grow (&pwtmpbuf)) ++ { ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } + # else +- p = getpwnam (user_name); ++ p = getpwnam (user_name); + # endif + +- if (__glibc_unlikely (malloc_user_name)) +- free (user_name); ++ if (__glibc_unlikely (malloc_user_name)) ++ free (user_name); + +- /* If we found a home directory use this. */ +- if (p != NULL) +- { +- size_t home_len = strlen (p->pw_dir); +- size_t rest_len = end_name == NULL ? 0 : strlen (end_name); +- char *d, *newp; +- bool use_alloca = glob_use_alloca (alloca_used, +- home_len + rest_len + 1); +- +- if (use_alloca) +- newp = alloca_account (home_len + rest_len + 1, alloca_used); +- else +- { +- newp = malloc (home_len + rest_len + 1); +- if (newp == NULL) +- { +- scratch_buffer_free (&pwtmpbuf); +- retval = GLOB_NOSPACE; +- goto out; +- } +- } +- d = mempcpy (newp, p->pw_dir, home_len); +- if (end_name != NULL) +- d = mempcpy (d, end_name, rest_len); +- *d = '\0'; +- +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- dirname = newp; +- malloc_dirname = !use_alloca; +- +- dirlen = home_len + rest_len; +- dirname_modified = 1; +- } +- else +- { +- if (flags & GLOB_TILDE_CHECK) +- { +- /* We have to regard it as an error if we cannot find the +- home directory. */ +- retval = GLOB_NOMATCH; +- goto out; +- } +- } +- scratch_buffer_free (&pwtmpbuf); +- } +-#endif /* !WINDOWS32 */ +- } ++ /* If we found a home directory use this. */ ++ if (p != NULL) ++ { ++ size_t home_len = strlen (p->pw_dir); ++ size_t rest_len = end_name == NULL ? 0 : strlen (end_name); ++ /* dirname contains end_name; we can't free it now. */ ++ char *prev_dirname = ++ (__glibc_unlikely (malloc_dirname) ? dirname : NULL); ++ char *d; ++ ++ malloc_dirname = 0; ++ ++ if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) ++ dirname = alloca_account (home_len + rest_len + 1, ++ alloca_used); ++ else ++ { ++ dirname = malloc (home_len + rest_len + 1); ++ if (dirname == NULL) ++ { ++ free (prev_dirname); ++ scratch_buffer_free (&pwtmpbuf); ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ malloc_dirname = 1; ++ } ++ d = mempcpy (dirname, p->pw_dir, home_len); ++ if (end_name != NULL) ++ d = mempcpy (d, end_name, rest_len); ++ *d = '\0'; ++ ++ free (prev_dirname); ++ ++ dirlen = home_len + rest_len; ++ dirname_modified = 1; ++ } ++ else ++ { ++ if (flags & GLOB_TILDE_CHECK) ++ { ++ /* We have to regard it as an error if we cannot find the ++ home directory. */ ++ retval = GLOB_NOMATCH; ++ goto out; ++ } ++ } ++ scratch_buffer_free (&pwtmpbuf); ++ } ++#else /* WINDOWS32 */ ++ /* On native Windows, access to a user's home directory ++ (via GetUserProfileDirectory) or to a user's environment ++ variables (via ExpandEnvironmentStringsForUser) requires ++ the credentials of the user. Therefore we cannot support ++ the ~user syntax on this platform. ++ Handling ~user specially (and treat it like plain ~) if ++ user is getenv ("USERNAME") would not be a good idea, ++ since it would make people think that ~user is supported ++ in general. */ ++ if (flags & GLOB_TILDE_CHECK) ++ { ++ retval = GLOB_NOMATCH; ++ goto out; ++ } ++#endif /* WINDOWS32 */ ++ } + } + + /* Now test whether we looked for "~" or "~NAME". In this case we + can give the answer now. */ + if (filename == NULL) + { +- size_t newcount = pglob->gl_pathc + pglob->gl_offs; +- char **new_gl_pathv; ++ size_t newcount = pglob->gl_pathc + pglob->gl_offs; ++ char **new_gl_pathv; ++ ++ if (newcount > SIZE_MAX / sizeof (char *) - 2) ++ { ++ nospace: ++ free (pglob->gl_pathv); ++ pglob->gl_pathv = NULL; ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } + +- if (newcount > SIZE_MAX / sizeof (char *) - 2) +- { +- nospace: +- free (pglob->gl_pathv); +- pglob->gl_pathv = NULL; +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- +- new_gl_pathv = realloc (pglob->gl_pathv, +- (newcount + 2) * sizeof (char *)); +- if (new_gl_pathv == NULL) +- goto nospace; +- pglob->gl_pathv = new_gl_pathv; +- +- if (flags & GLOB_MARK && is_dir (dirname, flags, pglob)) +- { +- char *p; +- pglob->gl_pathv[newcount] = malloc (dirlen + 2); +- if (pglob->gl_pathv[newcount] == NULL) +- goto nospace; +- p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); +- p[0] = '/'; +- p[1] = '\0'; +- if (__glibc_unlikely (malloc_dirname)) +- free (dirname); +- } +- else +- { +- if (__glibc_unlikely (malloc_dirname)) +- pglob->gl_pathv[newcount] = dirname; +- else +- { +- pglob->gl_pathv[newcount] = strdup (dirname); +- if (pglob->gl_pathv[newcount] == NULL) +- goto nospace; +- } +- } +- pglob->gl_pathv[++newcount] = NULL; +- ++pglob->gl_pathc; +- pglob->gl_flags = flags; ++ new_gl_pathv = realloc (pglob->gl_pathv, ++ (newcount + 2) * sizeof (char *)); ++ if (new_gl_pathv == NULL) ++ goto nospace; ++ pglob->gl_pathv = new_gl_pathv; ++ ++ if (flags & GLOB_MARK && is_dir (dirname, flags, pglob)) ++ { ++ char *p; ++ pglob->gl_pathv[newcount] = malloc (dirlen + 2); ++ if (pglob->gl_pathv[newcount] == NULL) ++ goto nospace; ++ p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); ++ p[0] = '/'; ++ p[1] = '\0'; ++ if (__glibc_unlikely (malloc_dirname)) ++ free (dirname); ++ } ++ else ++ { ++ if (__glibc_unlikely (malloc_dirname)) ++ pglob->gl_pathv[newcount] = dirname; ++ else ++ { ++ pglob->gl_pathv[newcount] = strdup (dirname); ++ if (pglob->gl_pathv[newcount] == NULL) ++ goto nospace; ++ } ++ } ++ pglob->gl_pathv[++newcount] = NULL; ++ ++pglob->gl_pathc; ++ pglob->gl_flags = flags; + +- return 0; ++ return 0; + } + + meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); +@@ -934,135 +969,135 @@ __glob (const char *pattern, int flags, + if (meta & (GLOBPAT_SPECIAL | GLOBPAT_BRACKET)) + { + /* The directory name contains metacharacters, so we +- have to glob for the directory, and then glob for +- the pattern in each directory found. */ ++ have to glob for the directory, and then glob for ++ the pattern in each directory found. */ + size_t i; + + if (!(flags & GLOB_NOESCAPE) && dirlen > 0 && dirname[dirlen - 1] == '\\') +- { +- /* "foo\\/bar". Remove the final backslash from dirname +- if it has not been quoted. */ +- char *p = (char *) &dirname[dirlen - 1]; +- +- while (p > dirname && p[-1] == '\\') --p; +- if ((&dirname[dirlen] - p) & 1) +- *(char *) &dirname[--dirlen] = '\0'; +- } ++ { ++ /* "foo\\/bar". Remove the final backslash from dirname ++ if it has not been quoted. */ ++ char *p = (char *) &dirname[dirlen - 1]; ++ ++ while (p > dirname && p[-1] == '\\') --p; ++ if ((&dirname[dirlen] - p) & 1) ++ *(char *) &dirname[--dirlen] = '\0'; ++ } + + if (__glibc_unlikely ((flags & GLOB_ALTDIRFUNC) != 0)) +- { +- /* Use the alternative access functions also in the recursive +- call. */ +- dirs.gl_opendir = pglob->gl_opendir; +- dirs.gl_readdir = pglob->gl_readdir; +- dirs.gl_closedir = pglob->gl_closedir; +- dirs.gl_stat = pglob->gl_stat; +- dirs.gl_lstat = pglob->gl_lstat; +- } ++ { ++ /* Use the alternative access functions also in the recursive ++ call. */ ++ dirs.gl_opendir = pglob->gl_opendir; ++ dirs.gl_readdir = pglob->gl_readdir; ++ dirs.gl_closedir = pglob->gl_closedir; ++ dirs.gl_stat = pglob->gl_stat; ++ dirs.gl_lstat = pglob->gl_lstat; ++ } + + status = __glob (dirname, +- ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) +- | GLOB_NOSORT | GLOB_ONLYDIR), +- errfunc, &dirs); ++ ((flags & (GLOB_ERR | GLOB_NOESCAPE | GLOB_ALTDIRFUNC)) ++ | GLOB_NOSORT | GLOB_ONLYDIR), ++ errfunc, &dirs); + if (status != 0) +- { +- if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) +- { +- retval = status; +- goto out; +- } +- goto no_matches; +- } ++ { ++ if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) ++ { ++ retval = status; ++ goto out; ++ } ++ goto no_matches; ++ } + + /* We have successfully globbed the preceding directory name. +- For each name we found, call glob_in_dir on it and FILENAME, +- appending the results to PGLOB. */ ++ For each name we found, call glob_in_dir on it and FILENAME, ++ appending the results to PGLOB. */ + for (i = 0; i < dirs.gl_pathc; ++i) +- { +- size_t old_pathc; ++ { ++ size_t old_pathc; + +- old_pathc = pglob->gl_pathc; +- status = glob_in_dir (filename, dirs.gl_pathv[i], +- ((flags | GLOB_APPEND) +- & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), +- errfunc, pglob, alloca_used); +- if (status == GLOB_NOMATCH) +- /* No matches in this directory. Try the next. */ +- continue; +- +- if (status != 0) +- { +- globfree (&dirs); +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = status; +- goto out; +- } +- +- /* Stick the directory on the front of each name. */ +- if (prefix_array (dirs.gl_pathv[i], +- &pglob->gl_pathv[old_pathc + pglob->gl_offs], +- pglob->gl_pathc - old_pathc)) +- { +- globfree (&dirs); +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- } ++ old_pathc = pglob->gl_pathc; ++ status = glob_in_dir (filename, dirs.gl_pathv[i], ++ ((flags | GLOB_APPEND) ++ & ~(GLOB_NOCHECK | GLOB_NOMAGIC)), ++ errfunc, pglob, alloca_used); ++ if (status == GLOB_NOMATCH) ++ /* No matches in this directory. Try the next. */ ++ continue; ++ ++ if (status != 0) ++ { ++ globfree (&dirs); ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = status; ++ goto out; ++ } ++ ++ /* Stick the directory on the front of each name. */ ++ if (prefix_array (dirs.gl_pathv[i], ++ &pglob->gl_pathv[old_pathc + pglob->gl_offs], ++ pglob->gl_pathc - old_pathc)) ++ { ++ globfree (&dirs); ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } + + flags |= GLOB_MAGCHAR; + + /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls. +- But if we have not found any matching entry and the GLOB_NOCHECK +- flag was set we must return the input pattern itself. */ ++ But if we have not found any matching entry and the GLOB_NOCHECK ++ flag was set we must return the input pattern itself. */ + if (pglob->gl_pathc + pglob->gl_offs == oldcount) +- { +- no_matches: +- /* No matches. */ +- if (flags & GLOB_NOCHECK) +- { +- size_t newcount = pglob->gl_pathc + pglob->gl_offs; +- char **new_gl_pathv; +- +- if (newcount > SIZE_MAX / sizeof (char *) - 2) +- { +- nospace2: +- globfree (&dirs); +- retval = GLOB_NOSPACE; +- goto out; +- } +- +- new_gl_pathv = realloc (pglob->gl_pathv, +- (newcount + 2) * sizeof (char *)); +- if (new_gl_pathv == NULL) +- goto nospace2; +- pglob->gl_pathv = new_gl_pathv; +- +- pglob->gl_pathv[newcount] = strdup (pattern); +- if (pglob->gl_pathv[newcount] == NULL) +- { +- globfree (&dirs); +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- +- ++pglob->gl_pathc; +- ++newcount; +- +- pglob->gl_pathv[newcount] = NULL; +- pglob->gl_flags = flags; +- } +- else +- { +- globfree (&dirs); +- retval = GLOB_NOMATCH; +- goto out; +- } +- } ++ { ++ no_matches: ++ /* No matches. */ ++ if (flags & GLOB_NOCHECK) ++ { ++ size_t newcount = pglob->gl_pathc + pglob->gl_offs; ++ char **new_gl_pathv; ++ ++ if (newcount > SIZE_MAX / sizeof (char *) - 2) ++ { ++ nospace2: ++ globfree (&dirs); ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ ++ new_gl_pathv = realloc (pglob->gl_pathv, ++ (newcount + 2) * sizeof (char *)); ++ if (new_gl_pathv == NULL) ++ goto nospace2; ++ pglob->gl_pathv = new_gl_pathv; ++ ++ pglob->gl_pathv[newcount] = strdup (pattern); ++ if (pglob->gl_pathv[newcount] == NULL) ++ { ++ globfree (&dirs); ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ ++ ++pglob->gl_pathc; ++ ++newcount; ++ ++ pglob->gl_pathv[newcount] = NULL; ++ pglob->gl_flags = flags; ++ } ++ else ++ { ++ globfree (&dirs); ++ retval = GLOB_NOMATCH; ++ goto out; ++ } ++ } + + globfree (&dirs); + } +@@ -1072,57 +1107,57 @@ __glob (const char *pattern, int flags, + int orig_flags = flags; + + if (meta & GLOBPAT_BACKSLASH) +- { +- char *p = strchr (dirname, '\\'), *q; +- /* We need to unescape the dirname string. It is certainly +- allocated by alloca, as otherwise filename would be NULL +- or dirname wouldn't contain backslashes. */ +- q = p; +- do +- { +- if (*p == '\\') +- { +- *q = *++p; +- --dirlen; +- } +- else +- *q = *p; +- ++q; +- } +- while (*p++ != '\0'); +- dirname_modified = 1; +- } ++ { ++ char *p = strchr (dirname, '\\'), *q; ++ /* We need to unescape the dirname string. It is certainly ++ allocated by alloca, as otherwise filename would be NULL ++ or dirname wouldn't contain backslashes. */ ++ q = p; ++ do ++ { ++ if (*p == '\\') ++ { ++ *q = *++p; ++ --dirlen; ++ } ++ else ++ *q = *p; ++ ++q; ++ } ++ while (*p++ != '\0'); ++ dirname_modified = 1; ++ } + if (dirname_modified) +- flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); ++ flags &= ~(GLOB_NOCHECK | GLOB_NOMAGIC); + status = glob_in_dir (filename, dirname, flags, errfunc, pglob, +- alloca_used); ++ alloca_used); + if (status != 0) +- { +- if (status == GLOB_NOMATCH && flags != orig_flags +- && pglob->gl_pathc + pglob->gl_offs == oldcount) +- { +- /* Make sure globfree (&dirs); is a nop. */ +- dirs.gl_pathv = NULL; +- flags = orig_flags; +- goto no_matches; +- } +- retval = status; +- goto out; +- } ++ { ++ if (status == GLOB_NOMATCH && flags != orig_flags ++ && pglob->gl_pathc + pglob->gl_offs == oldcount) ++ { ++ /* Make sure globfree (&dirs); is a nop. */ ++ dirs.gl_pathv = NULL; ++ flags = orig_flags; ++ goto no_matches; ++ } ++ retval = status; ++ goto out; ++ } + + if (dirlen > 0) +- { +- /* Stick the directory on the front of each name. */ +- if (prefix_array (dirname, +- &pglob->gl_pathv[old_pathc + pglob->gl_offs], +- pglob->gl_pathc - old_pathc)) +- { +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- } ++ { ++ /* Stick the directory on the front of each name. */ ++ if (prefix_array (dirname, ++ &pglob->gl_pathv[old_pathc + pglob->gl_offs], ++ pglob->gl_pathc - old_pathc)) ++ { ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ } + } + + if (flags & GLOB_MARK) +@@ -1131,28 +1166,28 @@ __glob (const char *pattern, int flags, + size_t i; + + for (i = oldcount; i < pglob->gl_pathc + pglob->gl_offs; ++i) +- if (is_dir (pglob->gl_pathv[i], flags, pglob)) +- { +- size_t len = strlen (pglob->gl_pathv[i]) + 2; +- char *new = realloc (pglob->gl_pathv[i], len); +- if (new == NULL) +- { +- globfree (pglob); +- pglob->gl_pathc = 0; +- retval = GLOB_NOSPACE; +- goto out; +- } +- strcpy (&new[len - 2], "/"); +- pglob->gl_pathv[i] = new; +- } ++ if (is_dir (pglob->gl_pathv[i], flags, pglob)) ++ { ++ size_t len = strlen (pglob->gl_pathv[i]) + 2; ++ char *new = realloc (pglob->gl_pathv[i], len); ++ if (new == NULL) ++ { ++ globfree (pglob); ++ pglob->gl_pathc = 0; ++ retval = GLOB_NOSPACE; ++ goto out; ++ } ++ strcpy (&new[len - 2], "/"); ++ pglob->gl_pathv[i] = new; ++ } + } + + if (!(flags & GLOB_NOSORT)) + { + /* Sort the vector. */ + qsort (&pglob->gl_pathv[oldcount], +- pglob->gl_pathc + pglob->gl_offs - oldcount, +- sizeof (char *), collated_compare); ++ pglob->gl_pathc + pglob->gl_offs - oldcount, ++ sizeof (char *), collated_compare); + } + + out: +@@ -1204,14 +1239,14 @@ prefix_array (const char *dirname, char + if (dirlen > 1) + { + if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') +- /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ +- --dirlen; ++ /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ ++ --dirlen; + else if (dirname[dirlen - 1] == ':') +- { +- /* DIRNAME is "d:". Use ':' instead of '/'. */ +- --dirlen; +- dirsep_char = ':'; +- } ++ { ++ /* DIRNAME is "d:". Use ':' instead of '/'. */ ++ --dirlen; ++ dirsep_char = ':'; ++ } + } + #endif + +@@ -1220,16 +1255,16 @@ prefix_array (const char *dirname, char + size_t eltlen = strlen (array[i]) + 1; + char *new = malloc (dirlen + 1 + eltlen); + if (new == NULL) +- { +- while (i > 0) +- free (array[--i]); +- return 1; +- } ++ { ++ while (i > 0) ++ free (array[--i]); ++ return 1; ++ } + + { +- char *endp = mempcpy (new, dirname, dirlen); +- *endp++ = dirsep_char; +- mempcpy (endp, array[i], eltlen); ++ char *endp = mempcpy (new, dirname, dirlen); ++ *endp++ = dirsep_char; ++ mempcpy (endp, array[i], eltlen); + } + free (array[i]); + array[i] = new; +@@ -1244,11 +1279,13 @@ prefix_array (const char *dirname, char + The GLOB_APPEND flag is assumed to be set (always appends). */ + static int + glob_in_dir (const char *pattern, const char *directory, int flags, +- int (*errfunc) (const char *, int), +- glob_t *pglob, size_t alloca_used) ++ int (*errfunc) (const char *, int), ++ glob_t *pglob, size_t alloca_used) + { + size_t dirlen = strlen (directory); + void *stream = NULL; ++ struct scratch_buffer s; ++ scratch_buffer_init (&s); + # define GLOBNAMES_MEMBERS(nnames) \ + struct globnames *next; size_t count; char *name[nnames]; + struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) }; +@@ -1273,8 +1310,8 @@ glob_in_dir (const char *pattern, const + if (meta == GLOBPAT_NONE && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) + { + /* We need not do any tests. The PATTERN contains no meta +- characters and we must not return an error therefore the +- result will always contain exactly one name. */ ++ characters and we must not return an error therefore the ++ result will always contain exactly one name. */ + flags |= GLOB_NOCHECK; + } + else if (meta == GLOBPAT_NONE) +@@ -1288,102 +1325,127 @@ glob_in_dir (const char *pattern, const + if (alloca_fullname) + fullname = alloca_account (fullsize, alloca_used); + else +- { +- fullname = malloc (fullsize); +- if (fullname == NULL) +- return GLOB_NOSPACE; +- } ++ { ++ fullname = malloc (fullsize); ++ if (fullname == NULL) ++ return GLOB_NOSPACE; ++ } + + mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), +- "/", 1), +- pattern, patlen + 1); ++ "/", 1), ++ pattern, patlen + 1); + if (glob_lstat (pglob, flags, fullname) == 0 +- || errno == EOVERFLOW) +- /* We found this file to be existing. Now tell the rest +- of the function to copy this name into the result. */ +- flags |= GLOB_NOCHECK; ++ || errno == EOVERFLOW) ++ /* We found this file to be existing. Now tell the rest ++ of the function to copy this name into the result. */ ++ flags |= GLOB_NOCHECK; + + if (__glibc_unlikely (!alloca_fullname)) +- free (fullname); ++ free (fullname); + } + else + { + stream = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) +- ? (*pglob->gl_opendir) (directory) +- : opendir (directory)); ++ ? (*pglob->gl_opendir) (directory) ++ : opendir (directory)); + if (stream == NULL) +- { +- if (errno != ENOTDIR +- && ((errfunc != NULL && (*errfunc) (directory, errno)) +- || (flags & GLOB_ERR))) +- return GLOB_ABORTED; +- } ++ { ++ if (errno != ENOTDIR ++ && ((errfunc != NULL && (*errfunc) (directory, errno)) ++ || (flags & GLOB_ERR))) ++ return GLOB_ABORTED; ++ } + else +- { +- int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) +- | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); +- flags |= GLOB_MAGCHAR; +- +- while (1) +- { +- struct readdir_result d; +- { +- if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) +- d = convert_dirent (GL_READDIR (pglob, stream)); +- else +- { ++ { ++ int dfd = dirfd (stream); ++ int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) ++ | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); ++ flags |= GLOB_MAGCHAR; ++ ++ while (1) ++ { ++ struct readdir_result d; ++ { ++ if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) ++ d = convert_dirent (GL_READDIR (pglob, stream)); ++ else ++ { + #ifdef COMPILE_GLOB64 +- d = convert_dirent (__readdir (stream)); ++ d = convert_dirent (__readdir (stream)); + #else +- d = convert_dirent64 (__readdir64 (stream)); ++ d = convert_dirent64 (__readdir64 (stream)); + #endif +- } +- } +- if (d.name == NULL) +- break; +- +- /* If we shall match only directories use the information +- provided by the dirent call if possible. */ +- if (flags & GLOB_ONLYDIR) +- switch (readdir_result_type (d)) +- { +- case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; +- default: continue; +- } +- +- if (fnmatch (pattern, d.name, fnm_flags) == 0) +- { +- if (cur == names->count) +- { +- struct globnames *newnames; +- size_t count = names->count * 2; +- size_t nameoff = offsetof (struct globnames, name); +- size_t size = FLEXSIZEOF (struct globnames, name, +- count * sizeof (char *)); +- if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) +- < names->count) +- goto memory_error; +- if (glob_use_alloca (alloca_used, size)) +- newnames = names_alloca +- = alloca_account (size, alloca_used); +- else if ((newnames = malloc (size)) +- == NULL) +- goto memory_error; +- newnames->count = count; +- newnames->next = names; +- names = newnames; +- cur = 0; +- } +- names->name[cur] = strdup (d.name); +- if (names->name[cur] == NULL) +- goto memory_error; +- ++cur; +- ++nfound; +- if (SIZE_MAX - pglob->gl_offs <= nfound) +- goto memory_error; +- } +- } +- } ++ } ++ } ++ if (d.name == NULL) ++ break; ++ ++ /* If we shall match only directories use the information ++ provided by the dirent call if possible. */ ++ if (flags & GLOB_ONLYDIR) ++ switch (readdir_result_type (d)) ++ { ++ default: continue; ++ case DT_DIR: break; ++ case DT_LNK: case DT_UNKNOWN: ++ /* The filesystem was too lazy to give us a hint, ++ so we have to do it the hard way. */ ++ if (__glibc_unlikely (dfd < 0 || flags & GLOB_ALTDIRFUNC)) ++ { ++ size_t namelen = strlen (d.name); ++ size_t need = dirlen + 1 + namelen + 1; ++ if (s.length < need ++ && !scratch_buffer_set_array_size (&s, need, 1)) ++ goto memory_error; ++ char *p = mempcpy (s.data, directory, dirlen); ++ *p = '/'; ++ p += p[-1] != '/'; ++ memcpy (p, d.name, namelen + 1); ++ if (! is_dir (s.data, flags, pglob)) ++ continue; ++ } ++ else ++ { ++ struct_stat64 st64; ++ if (! (GLOB_FSTATAT64 (dfd, d.name, &st64, 0) == 0 ++ && S_ISDIR (st64.st_mode))) ++ continue; ++ } ++ } ++ ++ if (fnmatch (pattern, d.name, fnm_flags) == 0) ++ { ++ if (cur == names->count) ++ { ++ struct globnames *newnames; ++ size_t count = names->count * 2; ++ size_t nameoff = offsetof (struct globnames, name); ++ size_t size = FLEXSIZEOF (struct globnames, name, ++ count * sizeof (char *)); ++ if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) ++ < names->count) ++ goto memory_error; ++ if (glob_use_alloca (alloca_used, size)) ++ newnames = names_alloca ++ = alloca_account (size, alloca_used); ++ else if ((newnames = malloc (size)) ++ == NULL) ++ goto memory_error; ++ newnames->count = count; ++ newnames->next = names; ++ names = newnames; ++ cur = 0; ++ } ++ names->name[cur] = strdup (d.name); ++ if (names->name[cur] == NULL) ++ goto memory_error; ++ ++cur; ++ ++nfound; ++ if (SIZE_MAX - pglob->gl_offs <= nfound) ++ goto memory_error; ++ } ++ } ++ } + } + + if (nfound == 0 && (flags & GLOB_NOCHECK)) +@@ -1392,7 +1454,7 @@ glob_in_dir (const char *pattern, const + nfound = 1; + names->name[cur] = malloc (len + 1); + if (names->name[cur] == NULL) +- goto memory_error; ++ goto memory_error; + *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; + } + +@@ -1403,82 +1465,83 @@ glob_in_dir (const char *pattern, const + result = 0; + + if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc +- < pglob->gl_offs + nfound + 1) +- goto memory_error; ++ < pglob->gl_offs + nfound + 1) ++ goto memory_error; + + new_gl_pathv +- = realloc (pglob->gl_pathv, +- (pglob->gl_pathc + pglob->gl_offs + nfound + 1) +- * sizeof (char *)); ++ = realloc (pglob->gl_pathv, ++ (pglob->gl_pathc + pglob->gl_offs + nfound + 1) ++ * sizeof (char *)); + + if (new_gl_pathv == NULL) +- { +- memory_error: +- while (1) +- { +- struct globnames *old = names; +- for (size_t i = 0; i < cur; ++i) +- free (names->name[i]); +- names = names->next; +- /* NB: we will not leak memory here if we exit without +- freeing the current block assigned to OLD. At least +- the very first block is always allocated on the stack +- and this is the block assigned to OLD here. */ +- if (names == NULL) +- { +- assert (old == init_names); +- break; +- } +- cur = names->count; +- if (old == names_alloca) +- names_alloca = names; +- else +- free (old); +- } +- result = GLOB_NOSPACE; +- } ++ { ++ memory_error: ++ while (1) ++ { ++ struct globnames *old = names; ++ for (size_t i = 0; i < cur; ++i) ++ free (names->name[i]); ++ names = names->next; ++ /* NB: we will not leak memory here if we exit without ++ freeing the current block assigned to OLD. At least ++ the very first block is always allocated on the stack ++ and this is the block assigned to OLD here. */ ++ if (names == NULL) ++ { ++ assert (old == init_names); ++ break; ++ } ++ cur = names->count; ++ if (old == names_alloca) ++ names_alloca = names; ++ else ++ free (old); ++ } ++ result = GLOB_NOSPACE; ++ } + else +- { +- while (1) +- { +- struct globnames *old = names; +- for (size_t i = 0; i < cur; ++i) +- new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] +- = names->name[i]; +- names = names->next; +- /* NB: we will not leak memory here if we exit without +- freeing the current block assigned to OLD. At least +- the very first block is always allocated on the stack +- and this is the block assigned to OLD here. */ +- if (names == NULL) +- { +- assert (old == init_names); +- break; +- } +- cur = names->count; +- if (old == names_alloca) +- names_alloca = names; +- else +- free (old); +- } ++ { ++ while (1) ++ { ++ struct globnames *old = names; ++ for (size_t i = 0; i < cur; ++i) ++ new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++] ++ = names->name[i]; ++ names = names->next; ++ /* NB: we will not leak memory here if we exit without ++ freeing the current block assigned to OLD. At least ++ the very first block is always allocated on the stack ++ and this is the block assigned to OLD here. */ ++ if (names == NULL) ++ { ++ assert (old == init_names); ++ break; ++ } ++ cur = names->count; ++ if (old == names_alloca) ++ names_alloca = names; ++ else ++ free (old); ++ } + +- pglob->gl_pathv = new_gl_pathv; ++ pglob->gl_pathv = new_gl_pathv; + +- pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; ++ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + +- pglob->gl_flags = flags; +- } ++ pglob->gl_flags = flags; ++ } + } + + if (stream != NULL) + { + save = errno; + if (__glibc_unlikely (flags & GLOB_ALTDIRFUNC)) +- (*pglob->gl_closedir) (stream); ++ (*pglob->gl_closedir) (stream); + else +- closedir (stream); ++ closedir (stream); + __set_errno (save); + } + ++ scratch_buffer_free (&s); + return result; + } +diff -rup a/sysdeps/gnu/glob-lstat-compat.c b/sysdeps/gnu/glob-lstat-compat.c +--- a/sysdeps/gnu/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/gnu/glob-lstat-compat.c 2022-05-02 17:51:04.167557574 -0400 +@@ -29,7 +29,8 @@ + #define GLOB_ATTRIBUTE attribute_compat_text_section + + /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */ +-#define GLOB_NO_LSTAT ++#define GLOB_LSTAT gl_stat ++#define GLOB_LSTAT64 __stat64 + + #include + +diff -rup a/sysdeps/unix/sysv/linux/glob-lstat-compat.c b/sysdeps/unix/sysv/linux/glob-lstat-compat.c +--- a/sysdeps/unix/sysv/linux/glob-lstat-compat.c 2018-08-01 01:10:47.000000000 -0400 ++++ b/sysdeps/unix/sysv/linux/glob-lstat-compat.c 2022-05-02 23:05:45.197297341 -0400 +@@ -30,7 +30,12 @@ + #define GLOB_ATTRIBUTE attribute_compat_text_section + + /* Avoid calling gl_lstat with GLOB_ALTDIRFUNC. */ +-#define GLOB_NO_LSTAT ++# define COMPILE_GLOB64 1 ++# define struct_stat struct stat ++# define struct_stat64 struct stat64 ++# define GLOB_LSTAT gl_stat ++# define GLOB_STAT64 __stat64 ++# define GLOB_LSTAT64 __stat64 + + #include + diff --git a/SOURCES/glibc-rh2033684-1.patch b/SOURCES/glibc-rh2033684-1.patch new file mode 100644 index 0000000..8734628 --- /dev/null +++ b/SOURCES/glibc-rh2033684-1.patch @@ -0,0 +1,27 @@ +commit 2a08b6e8331a611dc29325bfa6e29fecc9a3a46e +Author: Siddhesh Poyarekar +Date: Thu Dec 10 16:47:02 2020 +0530 + + Warn on unsupported fortification levels + + Make the _FORTIFY_SOURCE macro soup in features.h warn about + unsupported fortification levels. For example, it will warn about + _FORTIFY_SOURCE=3 and over with an indication of which level has been + selected. + + Co-authored-by: Paul Eggert + +diff --git a/include/features.h b/include/features.h +index 5bed0a499605a3a2..ea7673ee115bcf0a 100644 +--- a/include/features.h ++++ b/include/features.h +@@ -382,6 +382,9 @@ + # elif !__GNUC_PREREQ (4, 1) + # warning _FORTIFY_SOURCE requires GCC 4.1 or later + # elif _FORTIFY_SOURCE > 1 ++# if _FORTIFY_SOURCE > 2 ++# warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform ++# endif + # define __USE_FORTIFY_LEVEL 2 + # else + # define __USE_FORTIFY_LEVEL 1 diff --git a/SOURCES/glibc-rh2033684-10.patch b/SOURCES/glibc-rh2033684-10.patch new file mode 100644 index 0000000..94b4519 --- /dev/null +++ b/SOURCES/glibc-rh2033684-10.patch @@ -0,0 +1,90 @@ +commit 2bbd07c715275eb6c616988925738a0517180d57 +Author: Siddhesh Poyarekar +Date: Fri Dec 17 18:35:44 2021 +0530 + + fortify: Fix spurious warning with realpath + + The length and object size arguments were swapped around for realpath. + Also add a smoke test so that any changes in this area get caught in + future. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Adhemerval Zanella + +diff --git a/debug/Makefile b/debug/Makefile +index 81361438fc3d2aa9..b43f42ee3851f360 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -108,6 +108,7 @@ CFLAGS-tst-longjmp_chk2.c += -fexceptions -fasynchronous-unwind-tables + CPPFLAGS-tst-longjmp_chk2.c += -D_FORTIFY_SOURCE=1 + CFLAGS-tst-longjmp_chk3.c += -fexceptions -fasynchronous-unwind-tables + CPPFLAGS-tst-longjmp_chk3.c += -D_FORTIFY_SOURCE=1 ++CPPFLAGS-tst-realpath-chk.c += -D_FORTIFY_SOURCE=2 + + # We know these tests have problems with format strings, this is what + # we are testing. Disable that warning. They are also testing +@@ -155,7 +156,7 @@ tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \ + tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \ + tst-chk4 tst-chk5 tst-chk6 tst-chk7 tst-chk8 tst-lfschk4 tst-lfschk5 \ + tst-lfschk6 tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 \ +- tst-backtrace4 tst-backtrace5 tst-backtrace6 ++ tst-backtrace4 tst-backtrace5 tst-backtrace6 tst-realpath-chk + + ifeq ($(have-ssp),yes) + tests += tst-ssp-1 +diff --git a/debug/tst-realpath-chk.c b/debug/tst-realpath-chk.c +new file mode 100644 +index 0000000000000000..a8fcb327c43fb34d +--- /dev/null ++++ b/debug/tst-realpath-chk.c +@@ -0,0 +1,37 @@ ++/* Smoke test to verify that realpath does not cause spurious warnings. ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++#include ++#include ++ ++static int ++do_test (void) ++{ ++#ifdef PATH_MAX ++ char buf[PATH_MAX + 1]; ++ char *res = realpath (".", buf); ++ TEST_VERIFY (res == buf); ++#endif ++ ++ return 0; ++} ++ ++#include +diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h +index 7ea364a276497720..81ec9bdb32215e3b 100644 +--- a/stdlib/bits/stdlib.h ++++ b/stdlib/bits/stdlib.h +@@ -42,7 +42,7 @@ __NTH (realpath (const char *__restrict __name, char *__restrict __resolved)) + return __realpath_alias (__name, __resolved); + + #if defined _LIBC_LIMITS_H_ && defined PATH_MAX +- if (__glibc_unsafe_len (sz, sizeof (char), PATH_MAX)) ++ if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz)) + return __realpath_chk_warn (__name, __resolved, sz); + #endif + return __realpath_chk (__name, __resolved, sz); diff --git a/SOURCES/glibc-rh2033684-11.patch b/SOURCES/glibc-rh2033684-11.patch new file mode 100644 index 0000000..41ce66c --- /dev/null +++ b/SOURCES/glibc-rh2033684-11.patch @@ -0,0 +1,41 @@ +commit 86bf0feb0e3ec8e37872f72499d6ae33406561d7 +Author: Siddhesh Poyarekar +Date: Wed Jan 12 18:46:28 2022 +0530 + + Enable _FORTIFY_SOURCE=3 for gcc 12 and above + + gcc 12 now has support for the __builtin_dynamic_object_size builtin. + Adapt the macro checks to enable _FORTIFY_SOURCE=3 on gcc 12 and above. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Adhemerval Zanella + +diff --git a/include/features.h b/include/features.h +index fe9fe16d034fad1b..2e9ca6ec2f4a0380 100644 +--- a/include/features.h ++++ b/include/features.h +@@ -381,7 +381,9 @@ + # warning _FORTIFY_SOURCE requires compiling with optimization (-O) + # elif !__GNUC_PREREQ (4, 1) + # warning _FORTIFY_SOURCE requires GCC 4.1 or later +-# elif _FORTIFY_SOURCE > 2 && __glibc_clang_prereq (9, 0) ++# elif _FORTIFY_SOURCE > 2 && (__glibc_clang_prereq (9, 0) \ ++ || __GNUC_PREREQ (12, 0)) ++ + # if _FORTIFY_SOURCE > 3 + # warning _FORTIFY_SOURCE > 3 is treated like 3 on this platform + # endif +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 147339957c4ad490..a17ae0ed87e6163f 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -124,7 +124,8 @@ + #define __bos0(ptr) __builtin_object_size (ptr, 0) + + /* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available. */ +-#if __USE_FORTIFY_LEVEL == 3 && __glibc_clang_prereq (9, 0) ++#if __USE_FORTIFY_LEVEL == 3 && (__glibc_clang_prereq (9, 0) \ ++ || __GNUC_PREREQ (12, 0)) + # define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0) + # define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1) + #else diff --git a/SOURCES/glibc-rh2033684-12.patch b/SOURCES/glibc-rh2033684-12.patch new file mode 100644 index 0000000..9c9c98f --- /dev/null +++ b/SOURCES/glibc-rh2033684-12.patch @@ -0,0 +1,295 @@ +commit db27f1251b008280a29d540b4f8ab2a38a0d80af +Author: Siddhesh Poyarekar +Date: Wed Jan 12 23:34:23 2022 +0530 + + debug: Autogenerate _FORTIFY_SOURCE tests + + Rename debug/tst-chk1.c to debug/tst-fortify.c and add make hackery to + autogenerate tests with different macros enabled to build and run the + same test with different configurations as well as different + fortification levels. + + The change also ends up expanding the -lfs tests to include + _FORTIFY_SOURCE=3. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Adhemerval Zanella + +# Conflicts: +# debug/Makefile + +diff --git a/Makerules b/Makerules +index 5d6434c74bf9bfe5..05a549eb0f259113 100644 +--- a/Makerules ++++ b/Makerules +@@ -444,6 +444,12 @@ $(objpfx)%$o: $(objpfx)%.c $(before-compile); $$(compile-command.c) + endef + object-suffixes-left := $(all-object-suffixes) + include $(o-iterator) ++ ++define o-iterator-doit ++$(objpfx)%$o: $(objpfx)%.cc $(before-compile); $$(compile-command.cc) ++endef ++object-suffixes-left := $(all-object-suffixes) ++include $(o-iterator) + endif + + # Generate version maps, but wait until sysdep-subdirs is known +diff --git a/debug/Makefile b/debug/Makefile +index b43f42ee3851f360..c92fd23dda1a7279 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -1,4 +1,5 @@ +-# Copyright (C) 1998-2018 Free Software Foundation, Inc. ++# Copyright (C) 1998-2022 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. + # This file is part of the GNU C Library. + + # The GNU C Library is free software; you can redistribute it and/or +@@ -110,32 +111,60 @@ CFLAGS-tst-longjmp_chk3.c += -fexceptions -fasynchronous-unwind-tables + CPPFLAGS-tst-longjmp_chk3.c += -D_FORTIFY_SOURCE=1 + CPPFLAGS-tst-realpath-chk.c += -D_FORTIFY_SOURCE=2 + ++# _FORTIFY_SOURCE tests. ++# Auto-generate tests for _FORTIFY_SOURCE for different levels, compilers and ++# preprocessor conditions based on tst-fortify.c. ++# ++# To add a new test condition, define a cflags-$(cond) make variable to set ++# CFLAGS for the file. ++ ++tests-all-chk = tst-fortify ++tests-c-chk = ++tests-cc-chk = ++ ++CFLAGS-tst-fortify.c += -Wno-format -Wno-deprecated-declarations -Wno-error ++ ++# No additional flags for the default tests. ++define cflags-default ++endef ++ ++define cflags-lfs ++CFLAGS-tst-fortify-$(1)-lfs-$(2).$(1) += -D_FILE_OFFSET_BITS=64 ++endef ++ + # We know these tests have problems with format strings, this is what + # we are testing. Disable that warning. They are also testing + # deprecated functions (notably gets) so disable that warning as well. + # And they also generate warnings from warning attributes, which + # cannot be disabled via pragmas, so require -Wno-error to be used. +-CFLAGS-tst-chk1.c += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-chk2.c += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-chk3.c += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-chk4.cc += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-chk5.cc += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-chk6.cc += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-chk7.c += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-chk8.cc += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-lfschk1.c += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-lfschk2.c += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-lfschk3.c += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-lfschk4.cc += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-lfschk5.cc += -Wno-format -Wno-deprecated-declarations -Wno-error +-CFLAGS-tst-lfschk6.cc += -Wno-format -Wno-deprecated-declarations -Wno-error +-LDLIBS-tst-chk4 = -lstdc++ +-LDLIBS-tst-chk5 = -lstdc++ +-LDLIBS-tst-chk6 = -lstdc++ +-LDLIBS-tst-chk8 = -lstdc++ +-LDLIBS-tst-lfschk4 = -lstdc++ +-LDLIBS-tst-lfschk5 = -lstdc++ +-LDLIBS-tst-lfschk6 = -lstdc++ ++define gen-chk-test ++tests-$(1)-chk += tst-fortify-$(1)-$(2)-$(3) ++CFLAGS-tst-fortify-$(1)-$(2)-$(3).$(1) += -D_FORTIFY_SOURCE=$(3) -Wno-format \ ++ -Wno-deprecated-declarations \ ++ -Wno-error ++$(eval $(call cflags-$(2),$(1),$(3))) ++$(objpfx)tst-fortify-$(1)-$(2)-$(3).$(1): tst-fortify.c Makefile ++ ( echo "/* Autogenerated from Makefile. */"; \ ++ echo ""; \ ++ echo "#include \"tst-fortify.c\"" ) > $$@.tmp ++ mv $$@.tmp $$@ ++endef ++ ++chk-extensions = c cc ++chk-types = default lfs ++chk-levels = 1 2 3 ++ ++$(foreach e,$(chk-extensions), \ ++ $(foreach t,$(chk-types), \ ++ $(foreach l,$(chk-levels), \ ++ $(eval $(call gen-chk-test,$(e),$(t),$(l)))))) ++ ++tests-all-chk += $(tests-c-chk) $(tests-cc-chk) ++ ++define link-cc ++LDLIBS-$(1) = -lstdc++ ++endef ++$(foreach t,$(tests-cc-chk), $(eval $(call link-cc,$(t)))) + + # backtrace_symbols only works if we link with -rdynamic. backtrace + # requires unwind tables on most architectures. +@@ -152,19 +181,25 @@ LDFLAGS-tst-backtrace6 = -rdynamic + + CFLAGS-tst-ssp-1.c += -fstack-protector-all + +-tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \ +- tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \ +- tst-chk4 tst-chk5 tst-chk6 tst-chk7 tst-chk8 tst-lfschk4 tst-lfschk5 \ +- tst-lfschk6 tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 \ +- tst-backtrace4 tst-backtrace5 tst-backtrace6 tst-realpath-chk ++tests = backtrace-tst \ ++ tst-longjmp_chk \ ++ test-strcpy_chk \ ++ test-stpcpy_chk \ ++ tst-longjmp_chk2 \ ++ tst-backtrace2 \ ++ tst-backtrace3 \ ++ tst-backtrace4 \ ++ tst-backtrace5 \ ++ tst-backtrace6 \ ++ tst-realpath-chk \ ++ $(tests-all-chk) + + ifeq ($(have-ssp),yes) + tests += tst-ssp-1 + endif + + ifeq (,$(CXX)) +-tests-unsupported = tst-chk4 tst-chk5 tst-chk6 tst-chk8 \ +- tst-lfschk4 tst-lfschk5 tst-lfschk6 ++tests-unsupported = $(tests-cc-chk) + endif + + extra-libs = libSegFault libpcprofile +@@ -191,20 +226,10 @@ ifeq ($(run-built-tests),yes) + LOCALES := de_DE.UTF-8 + include ../gen-locales.mk + +-$(objpfx)tst-chk1.out: $(gen-locales) +-$(objpfx)tst-chk2.out: $(gen-locales) +-$(objpfx)tst-chk3.out: $(gen-locales) +-$(objpfx)tst-chk4.out: $(gen-locales) +-$(objpfx)tst-chk5.out: $(gen-locales) +-$(objpfx)tst-chk6.out: $(gen-locales) +-$(objpfx)tst-chk7.out: $(gen-locales) +-$(objpfx)tst-chk8.out: $(gen-locales) +-$(objpfx)tst-lfschk1.out: $(gen-locales) +-$(objpfx)tst-lfschk2.out: $(gen-locales) +-$(objpfx)tst-lfschk3.out: $(gen-locales) +-$(objpfx)tst-lfschk4.out: $(gen-locales) +-$(objpfx)tst-lfschk5.out: $(gen-locales) +-$(objpfx)tst-lfschk6.out: $(gen-locales) ++define chk-gen-locales ++$(objpfx)$(1).out: $(gen-locales) ++endef ++$(foreach t, $(tests-all-chk), $(eval $(call chk-gen-locales,$(t)))) + endif + + sLIBdir := $(shell echo $(slibdir) | sed 's,lib\(\|64\)$$,\\\\$$LIB,') +diff --git a/debug/tst-chk2.c b/debug/tst-chk2.c +deleted file mode 100644 +index be37ce2d22f0760a..0000000000000000 +--- a/debug/tst-chk2.c ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FORTIFY_SOURCE 1 +-#include "tst-chk1.c" +diff --git a/debug/tst-chk3.c b/debug/tst-chk3.c +deleted file mode 100644 +index 38b8e4fb360ba722..0000000000000000 +--- a/debug/tst-chk3.c ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FORTIFY_SOURCE 2 +-#include "tst-chk1.c" +diff --git a/debug/tst-chk4.cc b/debug/tst-chk4.cc +deleted file mode 100644 +index c82e6aac86038791..0000000000000000 +--- a/debug/tst-chk4.cc ++++ /dev/null +@@ -1 +0,0 @@ +-#include "tst-chk1.c" +diff --git a/debug/tst-chk5.cc b/debug/tst-chk5.cc +deleted file mode 100644 +index be37ce2d22f0760a..0000000000000000 +--- a/debug/tst-chk5.cc ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FORTIFY_SOURCE 1 +-#include "tst-chk1.c" +diff --git a/debug/tst-chk6.cc b/debug/tst-chk6.cc +deleted file mode 100644 +index 38b8e4fb360ba722..0000000000000000 +--- a/debug/tst-chk6.cc ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FORTIFY_SOURCE 2 +-#include "tst-chk1.c" +diff --git a/debug/tst-chk7.c b/debug/tst-chk7.c +deleted file mode 100644 +index 2a7b32381268135c..0000000000000000 +--- a/debug/tst-chk7.c ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FORTIFY_SOURCE 3 +-#include "tst-chk1.c" +diff --git a/debug/tst-chk8.cc b/debug/tst-chk8.cc +deleted file mode 100644 +index 2a7b32381268135c..0000000000000000 +--- a/debug/tst-chk8.cc ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FORTIFY_SOURCE 3 +-#include "tst-chk1.c" +diff --git a/debug/tst-chk1.c b/debug/tst-fortify.c +similarity index 100% +rename from debug/tst-chk1.c +rename to debug/tst-fortify.c +diff --git a/debug/tst-lfschk1.c b/debug/tst-lfschk1.c +deleted file mode 100644 +index f3e6d47d5e4484c3..0000000000000000 +--- a/debug/tst-lfschk1.c ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FILE_OFFSET_BITS 64 +-#include "tst-chk1.c" +diff --git a/debug/tst-lfschk2.c b/debug/tst-lfschk2.c +deleted file mode 100644 +index 95d4db1d32d2eeb3..0000000000000000 +--- a/debug/tst-lfschk2.c ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FILE_OFFSET_BITS 64 +-#include "tst-chk2.c" +diff --git a/debug/tst-lfschk3.c b/debug/tst-lfschk3.c +deleted file mode 100644 +index 50a1ae1258f1553d..0000000000000000 +--- a/debug/tst-lfschk3.c ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FILE_OFFSET_BITS 64 +-#include "tst-chk3.c" +diff --git a/debug/tst-lfschk4.cc b/debug/tst-lfschk4.cc +deleted file mode 100644 +index f3e6d47d5e4484c3..0000000000000000 +--- a/debug/tst-lfschk4.cc ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FILE_OFFSET_BITS 64 +-#include "tst-chk1.c" +diff --git a/debug/tst-lfschk5.cc b/debug/tst-lfschk5.cc +deleted file mode 100644 +index 95d4db1d32d2eeb3..0000000000000000 +--- a/debug/tst-lfschk5.cc ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FILE_OFFSET_BITS 64 +-#include "tst-chk2.c" +diff --git a/debug/tst-lfschk6.cc b/debug/tst-lfschk6.cc +deleted file mode 100644 +index 50a1ae1258f1553d..0000000000000000 +--- a/debug/tst-lfschk6.cc ++++ /dev/null +@@ -1,2 +0,0 @@ +-#define _FILE_OFFSET_BITS 64 +-#include "tst-chk3.c" diff --git a/SOURCES/glibc-rh2033684-2.patch b/SOURCES/glibc-rh2033684-2.patch new file mode 100644 index 0000000..4651008 --- /dev/null +++ b/SOURCES/glibc-rh2033684-2.patch @@ -0,0 +1,101 @@ +commit c43c5796121bc5bcc0867f02e5536874aa8196c1 +Author: Siddhesh Poyarekar +Date: Wed Dec 30 11:54:00 2020 +0530 + + Introduce _FORTIFY_SOURCE=3 + + Introduce a new _FORTIFY_SOURCE level of 3 to enable additional + fortifications that may have a noticeable performance impact, allowing + more fortification coverage at the cost of some performance. + + With llvm 9.0 or later, this will replace the use of + __builtin_object_size with __builtin_dynamic_object_size. + + __builtin_dynamic_object_size + ----------------------------- + + __builtin_dynamic_object_size is an LLVM builtin that is similar to + __builtin_object_size. In addition to what __builtin_object_size + does, i.e. replace the builtin call with a constant object size, + __builtin_dynamic_object_size will replace the call site with an + expression that evaluates to the object size, thus expanding its + applicability. In practice, __builtin_dynamic_object_size evaluates + these expressions through malloc/calloc calls that it can associate + with the object being evaluated. + + A simple motivating example is below; -D_FORTIFY_SOURCE=2 would miss + this and emit memcpy, but -D_FORTIFY_SOURCE=3 with the help of + __builtin_dynamic_object_size is able to emit __memcpy_chk with the + allocation size expression passed into the function: + + void *copy_obj (const void *src, size_t alloc, size_t copysize) + { + void *obj = malloc (alloc); + memcpy (obj, src, copysize); + return obj; + } + + Limitations + ----------- + + If the object was allocated elsewhere that the compiler cannot see, or + if it was allocated in the function with a function that the compiler + does not recognize as an allocator then __builtin_dynamic_object_size + also returns -1. + + Further, the expression used to compute object size may be non-trivial + and may potentially incur a noticeable performance impact. These + fortifications are hence enabled at a new _FORTIFY_SOURCE level to + allow developers to make a choice on the tradeoff according to their + environment. + +diff --git a/include/features.h b/include/features.h +index ea7673ee115bcf0a..fe9fe16d034fad1b 100644 +--- a/include/features.h ++++ b/include/features.h +@@ -381,6 +381,11 @@ + # warning _FORTIFY_SOURCE requires compiling with optimization (-O) + # elif !__GNUC_PREREQ (4, 1) + # warning _FORTIFY_SOURCE requires GCC 4.1 or later ++# elif _FORTIFY_SOURCE > 2 && __glibc_clang_prereq (9, 0) ++# if _FORTIFY_SOURCE > 3 ++# warning _FORTIFY_SOURCE > 3 is treated like 3 on this platform ++# endif ++# define __USE_FORTIFY_LEVEL 3 + # elif _FORTIFY_SOURCE > 1 + # if _FORTIFY_SOURCE > 2 + # warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform +diff --git a/manual/creature.texi b/manual/creature.texi +index 8876b2ab779c988f..64f361f27a7d6cdf 100644 +--- a/manual/creature.texi ++++ b/manual/creature.texi +@@ -247,7 +247,8 @@ included. + @standards{GNU, (none)} + If this macro is defined to @math{1}, security hardening is added to + various library functions. If defined to @math{2}, even stricter +-checks are applied. ++checks are applied. If defined to @math{3}, @theglibc{} may also use ++checks that may have an additional performance overhead. + @end defvr + + @defvr Macro _REENTRANT +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 3f6fe3cc8563b493..1e39307b0ebcf38f 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -123,6 +123,15 @@ + #define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1) + #define __bos0(ptr) __builtin_object_size (ptr, 0) + ++/* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available. */ ++#if __USE_FORTIFY_LEVEL == 3 && __glibc_clang_prereq (9, 0) ++# define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0) ++# define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1) ++#else ++# define __glibc_objsize0(__o) __bos0 (__o) ++# define __glibc_objsize(__o) __bos (__o) ++#endif ++ + #if __GNUC_PREREQ (4,3) + # define __warndecl(name, msg) \ + extern void name (void) __attribute__((__warning__ (msg))) diff --git a/SOURCES/glibc-rh2033684-3.patch b/SOURCES/glibc-rh2033684-3.patch new file mode 100644 index 0000000..b8d0093 --- /dev/null +++ b/SOURCES/glibc-rh2033684-3.patch @@ -0,0 +1,43 @@ +commit 7163ace3318d666d40771f5c8e7c4a148827070f +Author: Siddhesh Poyarekar +Date: Thu Nov 12 12:09:56 2020 +0530 + + Use __builtin___stpncpy_chk when available + + The builtin has been available in gcc since 4.7.0 and in clang since + 2.6. This fixes stpncpy fortification with clang since it does a + better job of plugging in __stpncpy_chk in the right place than the + header hackery. + + This has been tested by building and running all tests with gcc 10.2.1 + and also with clang tip as of a few days ago (just the tests in debug/ + since running all tests don't work with clang at the moment) to make + sure that both compilers pass the stpncpy tests. + +diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h +index a07ab0dbc8c8dd5b..4ed6755a6c1ca247 100644 +--- a/string/bits/string_fortified.h ++++ b/string/bits/string_fortified.h +@@ -106,7 +106,13 @@ __NTH (strncpy (char *__restrict __dest, const char *__restrict __src, + return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest)); + } + +-/* XXX We have no corresponding builtin yet. */ ++#if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6) ++__fortify_function char * ++__NTH (stpncpy (char *__dest, const char *__src, size_t __n)) ++{ ++ return __builtin___stpncpy_chk (__dest, __src, __n, __bos (__dest)); ++} ++#else + extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n, + size_t __destlen) __THROW; + extern char *__REDIRECT_NTH (__stpncpy_alias, (char *__dest, const char *__src, +@@ -120,6 +126,7 @@ __NTH (stpncpy (char *__dest, const char *__src, size_t __n)) + return __stpncpy_chk (__dest, __src, __n, __bos (__dest)); + return __stpncpy_alias (__dest, __src, __n); + } ++#endif + + + __fortify_function char * diff --git a/SOURCES/glibc-rh2033684-4.patch b/SOURCES/glibc-rh2033684-4.patch new file mode 100644 index 0000000..ebd0c33 --- /dev/null +++ b/SOURCES/glibc-rh2033684-4.patch @@ -0,0 +1,161 @@ +commit 2a3224c53653214cbba2ec23424702193c80ea3b +Author: Siddhesh Poyarekar +Date: Wed Dec 30 11:09:58 2020 +0530 + + string: Enable __FORTIFY_LEVEL=3 + + This change enhances fortified string functions to use + __builtin_dynamic_object_size under _FORTIFY_SOURCE=3 whenever the + compiler supports it. + +# Conflicts: +# string/bits/string_fortified.h + +Conflict resolved to retain __GNUC_PREREQ (5,0) macro check in RHEL-8 +glibc. + +diff --git a/include/string.h b/include/string.h +index 4d622f1c0305e78e..bbc97082661caf42 100644 +--- a/include/string.h ++++ b/include/string.h +@@ -119,10 +119,11 @@ libc_hidden_proto (__ffs) + void __explicit_bzero_chk_internal (void *, size_t, size_t) + __THROW __nonnull ((1)) attribute_hidden; + # define explicit_bzero(buf, len) \ +- __explicit_bzero_chk_internal (buf, len, __bos0 (buf)) ++ __explicit_bzero_chk_internal (buf, len, __glibc_objsize0 (buf)) + #elif !IS_IN (nonlib) + void __explicit_bzero_chk (void *, size_t, size_t) __THROW __nonnull ((1)); +-# define explicit_bzero(buf, len) __explicit_bzero_chk (buf, len, __bos0 (buf)) ++# define explicit_bzero(buf, len) __explicit_bzero_chk (buf, len, \ ++ __glibc_objsize0 (buf)) + #endif + + libc_hidden_builtin_proto (memchr) +diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h +index 4ed6755a6c1ca247..27ec273ec41cd81c 100644 +--- a/string/bits/string_fortified.h ++++ b/string/bits/string_fortified.h +@@ -31,13 +31,15 @@ __fortify_function void * + __NTH (memcpy (void *__restrict __dest, const void *__restrict __src, + size_t __len)) + { +- return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest)); ++ return __builtin___memcpy_chk (__dest, __src, __len, ++ __glibc_objsize0 (__dest)); + } + + __fortify_function void * + __NTH (memmove (void *__dest, const void *__src, size_t __len)) + { +- return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest)); ++ return __builtin___memmove_chk (__dest, __src, __len, ++ __glibc_objsize0 (__dest)); + } + + #ifdef __USE_GNU +@@ -45,7 +47,8 @@ __fortify_function void * + __NTH (mempcpy (void *__restrict __dest, const void *__restrict __src, + size_t __len)) + { +- return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest)); ++ return __builtin___mempcpy_chk (__dest, __src, __len, ++ __glibc_objsize0 (__dest)); + } + #endif + +@@ -68,7 +71,8 @@ __NTH (memset (void *__dest, int __ch, size_t __len)) + return __dest; + } + #endif +- return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest)); ++ return __builtin___memset_chk (__dest, __ch, __len, ++ __glibc_objsize0 (__dest)); + } + + #ifdef __USE_MISC +@@ -80,21 +84,21 @@ void __explicit_bzero_chk (void *__dest, size_t __len, size_t __destlen) + __fortify_function void + __NTH (explicit_bzero (void *__dest, size_t __len)) + { +- __explicit_bzero_chk (__dest, __len, __bos0 (__dest)); ++ __explicit_bzero_chk (__dest, __len, __glibc_objsize0 (__dest)); + } + #endif + + __fortify_function char * + __NTH (strcpy (char *__restrict __dest, const char *__restrict __src)) + { +- return __builtin___strcpy_chk (__dest, __src, __bos (__dest)); ++ return __builtin___strcpy_chk (__dest, __src, __glibc_objsize (__dest)); + } + + #ifdef __USE_GNU + __fortify_function char * + __NTH (stpcpy (char *__restrict __dest, const char *__restrict __src)) + { +- return __builtin___stpcpy_chk (__dest, __src, __bos (__dest)); ++ return __builtin___stpcpy_chk (__dest, __src, __glibc_objsize (__dest)); + } + #endif + +@@ -103,14 +107,16 @@ __fortify_function char * + __NTH (strncpy (char *__restrict __dest, const char *__restrict __src, + size_t __len)) + { +- return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest)); ++ return __builtin___strncpy_chk (__dest, __src, __len, ++ __glibc_objsize (__dest)); + } + + #if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6) + __fortify_function char * + __NTH (stpncpy (char *__dest, const char *__src, size_t __n)) + { +- return __builtin___stpncpy_chk (__dest, __src, __n, __bos (__dest)); ++ return __builtin___stpncpy_chk (__dest, __src, __n, ++ __glibc_objsize (__dest)); + } + #else + extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n, +@@ -132,7 +138,7 @@ __NTH (stpncpy (char *__dest, const char *__src, size_t __n)) + __fortify_function char * + __NTH (strcat (char *__restrict __dest, const char *__restrict __src)) + { +- return __builtin___strcat_chk (__dest, __src, __bos (__dest)); ++ return __builtin___strcat_chk (__dest, __src, __glibc_objsize (__dest)); + } + + +@@ -140,7 +146,8 @@ __fortify_function char * + __NTH (strncat (char *__restrict __dest, const char *__restrict __src, + size_t __len)) + { +- return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest)); ++ return __builtin___strncat_chk (__dest, __src, __len, ++ __glibc_objsize (__dest)); + } + + #endif /* bits/string_fortified.h */ +diff --git a/string/bits/strings_fortified.h b/string/bits/strings_fortified.h +index d9b2804525cfa994..871515bd2cba1f8a 100644 +--- a/string/bits/strings_fortified.h ++++ b/string/bits/strings_fortified.h +@@ -22,13 +22,15 @@ + __fortify_function void + __NTH (bcopy (const void *__src, void *__dest, size_t __len)) + { +- (void) __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest)); ++ (void) __builtin___memmove_chk (__dest, __src, __len, ++ __glibc_objsize0 (__dest)); + } + + __fortify_function void + __NTH (bzero (void *__dest, size_t __len)) + { +- (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest)); ++ (void) __builtin___memset_chk (__dest, '\0', __len, ++ __glibc_objsize0 (__dest)); + } + + #endif diff --git a/SOURCES/glibc-rh2033684-5.patch b/SOURCES/glibc-rh2033684-5.patch new file mode 100644 index 0000000..8c1f7f3 --- /dev/null +++ b/SOURCES/glibc-rh2033684-5.patch @@ -0,0 +1,963 @@ +commit f9de8bfe1a731c309b91d175b4f6f4aeb786effa +Author: Siddhesh Poyarekar +Date: Tue Dec 15 23:50:09 2020 +0530 + + nonstring: Enable __FORTIFY_LEVEL=3 + + Use __builtin_dynamic_object_size in the remaining functions that + don't have compiler builtins as is the case for string functions. + +diff --git a/io/bits/poll2.h b/io/bits/poll2.h +index 7e8406b87d6319f8..f47fd9ad0945234f 100644 +--- a/io/bits/poll2.h ++++ b/io/bits/poll2.h +@@ -35,12 +35,13 @@ extern int __REDIRECT (__poll_chk_warn, (struct pollfd *__fds, nfds_t __nfds, + __fortify_function int + poll (struct pollfd *__fds, nfds_t __nfds, int __timeout) + { +- if (__bos (__fds) != (__SIZE_TYPE__) -1) ++ if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1) + { + if (! __builtin_constant_p (__nfds)) +- return __poll_chk (__fds, __nfds, __timeout, __bos (__fds)); +- else if (__bos (__fds) / sizeof (*__fds) < __nfds) +- return __poll_chk_warn (__fds, __nfds, __timeout, __bos (__fds)); ++ return __poll_chk (__fds, __nfds, __timeout, __glibc_objsize (__fds)); ++ else if (__glibc_objsize (__fds) / sizeof (*__fds) < __nfds) ++ return __poll_chk_warn (__fds, __nfds, __timeout, ++ __glibc_objsize (__fds)); + } + + return __poll_alias (__fds, __nfds, __timeout); +@@ -65,13 +66,14 @@ __fortify_function int + ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout, + const __sigset_t *__ss) + { +- if (__bos (__fds) != (__SIZE_TYPE__) -1) ++ if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1) + { + if (! __builtin_constant_p (__nfds)) +- return __ppoll_chk (__fds, __nfds, __timeout, __ss, __bos (__fds)); +- else if (__bos (__fds) / sizeof (*__fds) < __nfds) ++ return __ppoll_chk (__fds, __nfds, __timeout, __ss, ++ __glibc_objsize (__fds)); ++ else if (__glibc_objsize (__fds) / sizeof (*__fds) < __nfds) + return __ppoll_chk_warn (__fds, __nfds, __timeout, __ss, +- __bos (__fds)); ++ __glibc_objsize (__fds)); + } + + return __ppoll_alias (__fds, __nfds, __timeout, __ss); +diff --git a/libio/bits/stdio.h b/libio/bits/stdio.h +index 4ab919031f77a960..1372d4bf70c43d53 100644 +--- a/libio/bits/stdio.h ++++ b/libio/bits/stdio.h +@@ -31,7 +31,7 @@ + + + #ifdef __USE_EXTERN_INLINES +-/* For -D_FORTIFY_SOURCE{,=2} bits/stdio2.h will define a different ++/* For -D_FORTIFY_SOURCE{,=2,=3} bits/stdio2.h will define a different + inline. */ + # if !(__USE_FORTIFY_LEVEL > 0 && defined __fortify_function) + /* Write formatted output to stdout from argument list ARG. */ +diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h +index 11651506a67daea0..2cd69f44cfadfc9f 100644 +--- a/libio/bits/stdio2.h ++++ b/libio/bits/stdio2.h +@@ -34,12 +34,13 @@ __fortify_function int + __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...)) + { + return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1, +- __bos (__s), __fmt, __va_arg_pack ()); ++ __glibc_objsize (__s), __fmt, ++ __va_arg_pack ()); + } + #elif !defined __cplusplus + # define sprintf(str, ...) \ +- __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1, __bos (str), \ +- __VA_ARGS__) ++ __builtin___sprintf_chk (str, __USE_FORTIFY_LEVEL - 1, \ ++ __glibc_objsize (str), __VA_ARGS__) + #endif + + __fortify_function int +@@ -47,7 +48,7 @@ __NTH (vsprintf (char *__restrict __s, const char *__restrict __fmt, + __gnuc_va_list __ap)) + { + return __builtin___vsprintf_chk (__s, __USE_FORTIFY_LEVEL - 1, +- __bos (__s), __fmt, __ap); ++ __glibc_objsize (__s), __fmt, __ap); + } + + #if defined __USE_ISOC99 || defined __USE_UNIX98 +@@ -65,12 +66,13 @@ __NTH (snprintf (char *__restrict __s, size_t __n, + const char *__restrict __fmt, ...)) + { + return __builtin___snprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, +- __bos (__s), __fmt, __va_arg_pack ()); ++ __glibc_objsize (__s), __fmt, ++ __va_arg_pack ()); + } + # elif !defined __cplusplus + # define snprintf(str, len, ...) \ +- __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, __bos (str), \ +- __VA_ARGS__) ++ __builtin___snprintf_chk (str, len, __USE_FORTIFY_LEVEL - 1, \ ++ __glibc_objsize (str), __VA_ARGS__) + # endif + + __fortify_function int +@@ -78,7 +80,7 @@ __NTH (vsnprintf (char *__restrict __s, size_t __n, + const char *__restrict __fmt, __gnuc_va_list __ap)) + { + return __builtin___vsnprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, +- __bos (__s), __fmt, __ap); ++ __glibc_objsize (__s), __fmt, __ap); + } + + #endif +@@ -234,8 +236,8 @@ extern char *__REDIRECT (__gets_warn, (char *__str), gets) + __fortify_function __wur char * + gets (char *__str) + { +- if (__bos (__str) != (size_t) -1) +- return __gets_chk (__str, __bos (__str)); ++ if (__glibc_objsize (__str) != (size_t) -1) ++ return __gets_chk (__str, __glibc_objsize (__str)); + return __gets_warn (__str); + } + #endif +@@ -254,13 +256,13 @@ extern char *__REDIRECT (__fgets_chk_warn, + __fortify_function __wur char * + fgets (char *__restrict __s, int __n, FILE *__restrict __stream) + { +- if (__bos (__s) != (size_t) -1) ++ if (__glibc_objsize (__s) != (size_t) -1) + { + if (!__builtin_constant_p (__n) || __n <= 0) +- return __fgets_chk (__s, __bos (__s), __n, __stream); ++ return __fgets_chk (__s, __glibc_objsize (__s), __n, __stream); + +- if ((size_t) __n > __bos (__s)) +- return __fgets_chk_warn (__s, __bos (__s), __n, __stream); ++ if ((size_t) __n > __glibc_objsize (__s)) ++ return __fgets_chk_warn (__s, __glibc_objsize (__s), __n, __stream); + } + return __fgets_alias (__s, __n, __stream); + } +@@ -284,15 +286,17 @@ __fortify_function __wur size_t + fread (void *__restrict __ptr, size_t __size, size_t __n, + FILE *__restrict __stream) + { +- if (__bos0 (__ptr) != (size_t) -1) ++ if (__glibc_objsize0 (__ptr) != (size_t) -1) + { + if (!__builtin_constant_p (__size) + || !__builtin_constant_p (__n) + || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2))) +- return __fread_chk (__ptr, __bos0 (__ptr), __size, __n, __stream); ++ return __fread_chk (__ptr, __glibc_objsize0 (__ptr), __size, __n, ++ __stream); + +- if (__size * __n > __bos0 (__ptr)) +- return __fread_chk_warn (__ptr, __bos0 (__ptr), __size, __n, __stream); ++ if (__size * __n > __glibc_objsize0 (__ptr)) ++ return __fread_chk_warn (__ptr, __glibc_objsize0 (__ptr), __size, __n, ++ __stream); + } + return __fread_alias (__ptr, __size, __n, __stream); + } +@@ -312,13 +316,15 @@ extern char *__REDIRECT (__fgets_unlocked_chk_warn, + __fortify_function __wur char * + fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream) + { +- if (__bos (__s) != (size_t) -1) ++ if (__glibc_objsize (__s) != (size_t) -1) + { + if (!__builtin_constant_p (__n) || __n <= 0) +- return __fgets_unlocked_chk (__s, __bos (__s), __n, __stream); ++ return __fgets_unlocked_chk (__s, __glibc_objsize (__s), __n, ++ __stream); + +- if ((size_t) __n > __bos (__s)) +- return __fgets_unlocked_chk_warn (__s, __bos (__s), __n, __stream); ++ if ((size_t) __n > __glibc_objsize (__s)) ++ return __fgets_unlocked_chk_warn (__s, __glibc_objsize (__s), __n, ++ __stream); + } + return __fgets_unlocked_alias (__s, __n, __stream); + } +@@ -345,17 +351,17 @@ __fortify_function __wur size_t + fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n, + FILE *__restrict __stream) + { +- if (__bos0 (__ptr) != (size_t) -1) ++ if (__glibc_objsize0 (__ptr) != (size_t) -1) + { + if (!__builtin_constant_p (__size) + || !__builtin_constant_p (__n) + || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2))) +- return __fread_unlocked_chk (__ptr, __bos0 (__ptr), __size, __n, +- __stream); ++ return __fread_unlocked_chk (__ptr, __glibc_objsize0 (__ptr), __size, ++ __n, __stream); + +- if (__size * __n > __bos0 (__ptr)) +- return __fread_unlocked_chk_warn (__ptr, __bos0 (__ptr), __size, __n, +- __stream); ++ if (__size * __n > __glibc_objsize0 (__ptr)) ++ return __fread_unlocked_chk_warn (__ptr, __glibc_objsize0 (__ptr), ++ __size, __n, __stream); + } + + # ifdef __USE_EXTERN_INLINES +diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h +index 9a749dccf8de65cd..a0c4dcfe9c61a7b8 100644 +--- a/posix/bits/unistd.h ++++ b/posix/bits/unistd.h +@@ -33,13 +33,14 @@ extern ssize_t __REDIRECT (__read_chk_warn, + __fortify_function __wur ssize_t + read (int __fd, void *__buf, size_t __nbytes) + { +- if (__bos0 (__buf) != (size_t) -1) ++ if (__glibc_objsize0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__nbytes)) +- return __read_chk (__fd, __buf, __nbytes, __bos0 (__buf)); ++ return __read_chk (__fd, __buf, __nbytes, __glibc_objsize0 (__buf)); + +- if (__nbytes > __bos0 (__buf)) +- return __read_chk_warn (__fd, __buf, __nbytes, __bos0 (__buf)); ++ if (__nbytes > __glibc_objsize0 (__buf)) ++ return __read_chk_warn (__fd, __buf, __nbytes, ++ __glibc_objsize0 (__buf)); + } + return __read_alias (__fd, __buf, __nbytes); + } +@@ -71,14 +72,15 @@ extern ssize_t __REDIRECT (__pread64_chk_warn, + __fortify_function __wur ssize_t + pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset) + { +- if (__bos0 (__buf) != (size_t) -1) ++ if (__glibc_objsize0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__nbytes)) +- return __pread_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); ++ return __pread_chk (__fd, __buf, __nbytes, __offset, ++ __glibc_objsize0 (__buf)); + +- if ( __nbytes > __bos0 (__buf)) ++ if ( __nbytes > __glibc_objsize0 (__buf)) + return __pread_chk_warn (__fd, __buf, __nbytes, __offset, +- __bos0 (__buf)); ++ __glibc_objsize0 (__buf)); + } + return __pread_alias (__fd, __buf, __nbytes, __offset); + } +@@ -86,14 +88,15 @@ pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset) + __fortify_function __wur ssize_t + pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) + { +- if (__bos0 (__buf) != (size_t) -1) ++ if (__glibc_objsize0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__nbytes)) +- return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); ++ return __pread64_chk (__fd, __buf, __nbytes, __offset, ++ __glibc_objsize0 (__buf)); + +- if ( __nbytes > __bos0 (__buf)) ++ if ( __nbytes > __glibc_objsize0 (__buf)) + return __pread64_chk_warn (__fd, __buf, __nbytes, __offset, +- __bos0 (__buf)); ++ __glibc_objsize0 (__buf)); + } + + return __pread64_alias (__fd, __buf, __nbytes, __offset); +@@ -104,14 +107,15 @@ pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) + __fortify_function __wur ssize_t + pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) + { +- if (__bos0 (__buf) != (size_t) -1) ++ if (__glibc_objsize0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__nbytes)) +- return __pread64_chk (__fd, __buf, __nbytes, __offset, __bos0 (__buf)); ++ return __pread64_chk (__fd, __buf, __nbytes, __offset, ++ __glibc_objsize0 (__buf)); + +- if ( __nbytes > __bos0 (__buf)) ++ if ( __nbytes > __glibc_objsize0 (__buf)) + return __pread64_chk_warn (__fd, __buf, __nbytes, __offset, +- __bos0 (__buf)); ++ __glibc_objsize0 (__buf)); + } + + return __pread64_alias (__fd, __buf, __nbytes, __offset); +@@ -139,13 +143,14 @@ __fortify_function __nonnull ((1, 2)) __wur ssize_t + __NTH (readlink (const char *__restrict __path, char *__restrict __buf, + size_t __len)) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) +- return __readlink_chk (__path, __buf, __len, __bos (__buf)); ++ return __readlink_chk (__path, __buf, __len, __glibc_objsize (__buf)); + +- if ( __len > __bos (__buf)) +- return __readlink_chk_warn (__path, __buf, __len, __bos (__buf)); ++ if ( __len > __glibc_objsize (__buf)) ++ return __readlink_chk_warn (__path, __buf, __len, ++ __glibc_objsize (__buf)); + } + return __readlink_alias (__path, __buf, __len); + } +@@ -173,14 +178,15 @@ __fortify_function __nonnull ((2, 3)) __wur ssize_t + __NTH (readlinkat (int __fd, const char *__restrict __path, + char *__restrict __buf, size_t __len)) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) +- return __readlinkat_chk (__fd, __path, __buf, __len, __bos (__buf)); ++ return __readlinkat_chk (__fd, __path, __buf, __len, ++ __glibc_objsize (__buf)); + +- if (__len > __bos (__buf)) ++ if (__len > __glibc_objsize (__buf)) + return __readlinkat_chk_warn (__fd, __path, __buf, __len, +- __bos (__buf)); ++ __glibc_objsize (__buf)); + } + return __readlinkat_alias (__fd, __path, __buf, __len); + } +@@ -199,13 +205,13 @@ extern char *__REDIRECT_NTH (__getcwd_chk_warn, + __fortify_function __wur char * + __NTH (getcwd (char *__buf, size_t __size)) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__size)) +- return __getcwd_chk (__buf, __size, __bos (__buf)); ++ return __getcwd_chk (__buf, __size, __glibc_objsize (__buf)); + +- if (__size > __bos (__buf)) +- return __getcwd_chk_warn (__buf, __size, __bos (__buf)); ++ if (__size > __glibc_objsize (__buf)) ++ return __getcwd_chk_warn (__buf, __size, __glibc_objsize (__buf)); + } + return __getcwd_alias (__buf, __size); + } +@@ -220,8 +226,8 @@ extern char *__REDIRECT_NTH (__getwd_warn, (char *__buf), getwd) + __fortify_function __nonnull ((1)) __attribute_deprecated__ __wur char * + __NTH (getwd (char *__buf)) + { +- if (__bos (__buf) != (size_t) -1) +- return __getwd_chk (__buf, __bos (__buf)); ++ if (__glibc_objsize (__buf) != (size_t) -1) ++ return __getwd_chk (__buf, __glibc_objsize (__buf)); + return __getwd_warn (__buf); + } + #endif +@@ -239,13 +245,14 @@ extern size_t __REDIRECT_NTH (__confstr_chk_warn, + __fortify_function size_t + __NTH (confstr (int __name, char *__buf, size_t __len)) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) +- return __confstr_chk (__name, __buf, __len, __bos (__buf)); ++ return __confstr_chk (__name, __buf, __len, __glibc_objsize (__buf)); + +- if (__bos (__buf) < __len) +- return __confstr_chk_warn (__name, __buf, __len, __bos (__buf)); ++ if (__glibc_objsize (__buf) < __len) ++ return __confstr_chk_warn (__name, __buf, __len, ++ __glibc_objsize (__buf)); + } + return __confstr_alias (__name, __buf, __len); + } +@@ -264,13 +271,13 @@ extern int __REDIRECT_NTH (__getgroups_chk_warn, + __fortify_function int + __NTH (getgroups (int __size, __gid_t __list[])) + { +- if (__bos (__list) != (size_t) -1) ++ if (__glibc_objsize (__list) != (size_t) -1) + { + if (!__builtin_constant_p (__size) || __size < 0) +- return __getgroups_chk (__size, __list, __bos (__list)); ++ return __getgroups_chk (__size, __list, __glibc_objsize (__list)); + +- if (__size * sizeof (__gid_t) > __bos (__list)) +- return __getgroups_chk_warn (__size, __list, __bos (__list)); ++ if (__size * sizeof (__gid_t) > __glibc_objsize (__list)) ++ return __getgroups_chk_warn (__size, __list, __glibc_objsize (__list)); + } + return __getgroups_alias (__size, __list); + } +@@ -290,13 +297,15 @@ extern int __REDIRECT_NTH (__ttyname_r_chk_warn, + __fortify_function int + __NTH (ttyname_r (int __fd, char *__buf, size_t __buflen)) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) +- return __ttyname_r_chk (__fd, __buf, __buflen, __bos (__buf)); ++ return __ttyname_r_chk (__fd, __buf, __buflen, ++ __glibc_objsize (__buf)); + +- if (__buflen > __bos (__buf)) +- return __ttyname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf)); ++ if (__buflen > __glibc_objsize (__buf)) ++ return __ttyname_r_chk_warn (__fd, __buf, __buflen, ++ __glibc_objsize (__buf)); + } + return __ttyname_r_alias (__fd, __buf, __buflen); + } +@@ -316,13 +325,14 @@ extern int __REDIRECT (__getlogin_r_chk_warn, + __fortify_function int + getlogin_r (char *__buf, size_t __buflen) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) +- return __getlogin_r_chk (__buf, __buflen, __bos (__buf)); ++ return __getlogin_r_chk (__buf, __buflen, __glibc_objsize (__buf)); + +- if (__buflen > __bos (__buf)) +- return __getlogin_r_chk_warn (__buf, __buflen, __bos (__buf)); ++ if (__buflen > __glibc_objsize (__buf)) ++ return __getlogin_r_chk_warn (__buf, __buflen, ++ __glibc_objsize (__buf)); + } + return __getlogin_r_alias (__buf, __buflen); + } +@@ -343,13 +353,14 @@ extern int __REDIRECT_NTH (__gethostname_chk_warn, + __fortify_function int + __NTH (gethostname (char *__buf, size_t __buflen)) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) +- return __gethostname_chk (__buf, __buflen, __bos (__buf)); ++ return __gethostname_chk (__buf, __buflen, __glibc_objsize (__buf)); + +- if (__buflen > __bos (__buf)) +- return __gethostname_chk_warn (__buf, __buflen, __bos (__buf)); ++ if (__buflen > __glibc_objsize (__buf)) ++ return __gethostname_chk_warn (__buf, __buflen, ++ __glibc_objsize (__buf)); + } + return __gethostname_alias (__buf, __buflen); + } +@@ -372,13 +383,14 @@ extern int __REDIRECT_NTH (__getdomainname_chk_warn, + __fortify_function int + __NTH (getdomainname (char *__buf, size_t __buflen)) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) +- return __getdomainname_chk (__buf, __buflen, __bos (__buf)); ++ return __getdomainname_chk (__buf, __buflen, __glibc_objsize (__buf)); + +- if (__buflen > __bos (__buf)) +- return __getdomainname_chk_warn (__buf, __buflen, __bos (__buf)); ++ if (__buflen > __glibc_objsize (__buf)) ++ return __getdomainname_chk_warn (__buf, __buflen, ++ __glibc_objsize (__buf)); + } + return __getdomainname_alias (__buf, __buflen); + } +diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h +index a129e697352fd7cb..729e5a4cc1f4cb92 100644 +--- a/socket/bits/socket2.h ++++ b/socket/bits/socket2.h +@@ -33,13 +33,15 @@ extern ssize_t __REDIRECT (__recv_chk_warn, + __fortify_function ssize_t + recv (int __fd, void *__buf, size_t __n, int __flags) + { +- if (__bos0 (__buf) != (size_t) -1) ++ if (__glibc_objsize0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__n)) +- return __recv_chk (__fd, __buf, __n, __bos0 (__buf), __flags); ++ return __recv_chk (__fd, __buf, __n, __glibc_objsize0 (__buf), ++ __flags); + +- if (__n > __bos0 (__buf)) +- return __recv_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags); ++ if (__n > __glibc_objsize0 (__buf)) ++ return __recv_chk_warn (__fd, __buf, __n, __glibc_objsize0 (__buf), ++ __flags); + } + return __recv_alias (__fd, __buf, __n, __flags); + } +@@ -64,14 +66,14 @@ __fortify_function ssize_t + recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags, + __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len) + { +- if (__bos0 (__buf) != (size_t) -1) ++ if (__glibc_objsize0 (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__n)) +- return __recvfrom_chk (__fd, __buf, __n, __bos0 (__buf), __flags, +- __addr, __addr_len); +- if (__n > __bos0 (__buf)) +- return __recvfrom_chk_warn (__fd, __buf, __n, __bos0 (__buf), __flags, +- __addr, __addr_len); ++ return __recvfrom_chk (__fd, __buf, __n, __glibc_objsize0 (__buf), ++ __flags, __addr, __addr_len); ++ if (__n > __glibc_objsize0 (__buf)) ++ return __recvfrom_chk_warn (__fd, __buf, __n, __glibc_objsize0 (__buf), ++ __flags, __addr, __addr_len); + } + return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len); + } +diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h +index 53c379b99ae9d5fe..5e4114ded33f2033 100644 +--- a/stdlib/bits/stdlib.h ++++ b/stdlib/bits/stdlib.h +@@ -36,13 +36,14 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn, + __fortify_function __wur char * + __NTH (realpath (const char *__restrict __name, char *__restrict __resolved)) + { +- if (__bos (__resolved) != (size_t) -1) ++ if (__glibc_objsize (__resolved) != (size_t) -1) + { + #if defined _LIBC_LIMITS_H_ && defined PATH_MAX +- if (__bos (__resolved) < PATH_MAX) +- return __realpath_chk_warn (__name, __resolved, __bos (__resolved)); ++ if (__glibc_objsize (__resolved) < PATH_MAX) ++ return __realpath_chk_warn (__name, __resolved, ++ __glibc_objsize (__resolved)); + #endif +- return __realpath_chk (__name, __resolved, __bos (__resolved)); ++ return __realpath_chk (__name, __resolved, __glibc_objsize (__resolved)); + } + + return __realpath_alias (__name, __resolved); +@@ -63,12 +64,14 @@ extern int __REDIRECT_NTH (__ptsname_r_chk_warn, + __fortify_function int + __NTH (ptsname_r (int __fd, char *__buf, size_t __buflen)) + { +- if (__bos (__buf) != (size_t) -1) ++ if (__glibc_objsize (__buf) != (size_t) -1) + { + if (!__builtin_constant_p (__buflen)) +- return __ptsname_r_chk (__fd, __buf, __buflen, __bos (__buf)); +- if (__buflen > __bos (__buf)) +- return __ptsname_r_chk_warn (__fd, __buf, __buflen, __bos (__buf)); ++ return __ptsname_r_chk (__fd, __buf, __buflen, ++ __glibc_objsize (__buf)); ++ if (__buflen > __glibc_objsize (__buf)) ++ return __ptsname_r_chk_warn (__fd, __buf, __buflen, ++ __glibc_objsize (__buf)); + } + return __ptsname_r_alias (__fd, __buf, __buflen); + } +@@ -89,8 +92,9 @@ __NTH (wctomb (char *__s, wchar_t __wchar)) + #if defined MB_LEN_MAX && MB_LEN_MAX != __STDLIB_MB_LEN_MAX + # error "Assumed value of MB_LEN_MAX wrong" + #endif +- if (__bos (__s) != (size_t) -1 && __STDLIB_MB_LEN_MAX > __bos (__s)) +- return __wctomb_chk (__s, __wchar, __bos (__s)); ++ if (__glibc_objsize (__s) != (size_t) -1 ++ && __STDLIB_MB_LEN_MAX > __glibc_objsize (__s)) ++ return __wctomb_chk (__s, __wchar, __glibc_objsize (__s)); + return __wctomb_alias (__s, __wchar); + } + +@@ -113,15 +117,16 @@ __fortify_function size_t + __NTH (mbstowcs (wchar_t *__restrict __dst, const char *__restrict __src, + size_t __len)) + { +- if (__bos (__dst) != (size_t) -1) ++ if (__glibc_objsize (__dst) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) + return __mbstowcs_chk (__dst, __src, __len, +- __bos (__dst) / sizeof (wchar_t)); ++ __glibc_objsize (__dst) / sizeof (wchar_t)); + +- if (__len > __bos (__dst) / sizeof (wchar_t)) ++ if (__len > __glibc_objsize (__dst) / sizeof (wchar_t)) + return __mbstowcs_chk_warn (__dst, __src, __len, +- __bos (__dst) / sizeof (wchar_t)); ++ (__glibc_objsize (__dst) ++ / sizeof (wchar_t))); + } + return __mbstowcs_alias (__dst, __src, __len); + } +@@ -144,12 +149,13 @@ __fortify_function size_t + __NTH (wcstombs (char *__restrict __dst, const wchar_t *__restrict __src, + size_t __len)) + { +- if (__bos (__dst) != (size_t) -1) ++ if (__glibc_objsize (__dst) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) +- return __wcstombs_chk (__dst, __src, __len, __bos (__dst)); +- if (__len > __bos (__dst)) +- return __wcstombs_chk_warn (__dst, __src, __len, __bos (__dst)); ++ return __wcstombs_chk (__dst, __src, __len, __glibc_objsize (__dst)); ++ if (__len > __glibc_objsize (__dst)) ++ return __wcstombs_chk_warn (__dst, __src, __len, ++ __glibc_objsize (__dst)); + } + return __wcstombs_alias (__dst, __src, __len); + } +diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h +index d62b86de3e288d53..838ba877ee4b4afe 100644 +--- a/wcsmbs/bits/wchar2.h ++++ b/wcsmbs/bits/wchar2.h +@@ -39,15 +39,15 @@ __fortify_function wchar_t * + __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + size_t __n)) + { +- if (__bos0 (__s1) != (size_t) -1) ++ if (__glibc_objsize0 (__s1) != (size_t) -1) + { + if (!__builtin_constant_p (__n)) + return __wmemcpy_chk (__s1, __s2, __n, +- __bos0 (__s1) / sizeof (wchar_t)); ++ __glibc_objsize0 (__s1) / sizeof (wchar_t)); + +- if (__n > __bos0 (__s1) / sizeof (wchar_t)) ++ if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t)) + return __wmemcpy_chk_warn (__s1, __s2, __n, +- __bos0 (__s1) / sizeof (wchar_t)); ++ __glibc_objsize0 (__s1) / sizeof (wchar_t)); + } + return __wmemcpy_alias (__s1, __s2, __n); + } +@@ -67,15 +67,16 @@ extern wchar_t *__REDIRECT_NTH (__wmemmove_chk_warn, + __fortify_function wchar_t * + __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n)) + { +- if (__bos0 (__s1) != (size_t) -1) ++ if (__glibc_objsize0 (__s1) != (size_t) -1) + { + if (!__builtin_constant_p (__n)) + return __wmemmove_chk (__s1, __s2, __n, +- __bos0 (__s1) / sizeof (wchar_t)); ++ __glibc_objsize0 (__s1) / sizeof (wchar_t)); + +- if (__n > __bos0 (__s1) / sizeof (wchar_t)) ++ if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t)) + return __wmemmove_chk_warn (__s1, __s2, __n, +- __bos0 (__s1) / sizeof (wchar_t)); ++ (__glibc_objsize0 (__s1) ++ / sizeof (wchar_t))); + } + return __wmemmove_alias (__s1, __s2, __n); + } +@@ -100,15 +101,16 @@ __fortify_function wchar_t * + __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + size_t __n)) + { +- if (__bos0 (__s1) != (size_t) -1) ++ if (__glibc_objsize0 (__s1) != (size_t) -1) + { + if (!__builtin_constant_p (__n)) + return __wmempcpy_chk (__s1, __s2, __n, +- __bos0 (__s1) / sizeof (wchar_t)); ++ __glibc_objsize0 (__s1) / sizeof (wchar_t)); + +- if (__n > __bos0 (__s1) / sizeof (wchar_t)) ++ if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t)) + return __wmempcpy_chk_warn (__s1, __s2, __n, +- __bos0 (__s1) / sizeof (wchar_t)); ++ (__glibc_objsize0 (__s1) ++ / sizeof (wchar_t))); + } + return __wmempcpy_alias (__s1, __s2, __n); + } +@@ -128,14 +130,15 @@ extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn, + __fortify_function wchar_t * + __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n)) + { +- if (__bos0 (__s) != (size_t) -1) ++ if (__glibc_objsize0 (__s) != (size_t) -1) + { + if (!__builtin_constant_p (__n)) +- return __wmemset_chk (__s, __c, __n, __bos0 (__s) / sizeof (wchar_t)); ++ return __wmemset_chk (__s, __c, __n, ++ __glibc_objsize0 (__s) / sizeof (wchar_t)); + +- if (__n > __bos0 (__s) / sizeof (wchar_t)) ++ if (__n > __glibc_objsize0 (__s) / sizeof (wchar_t)) + return __wmemset_chk_warn (__s, __c, __n, +- __bos0 (__s) / sizeof (wchar_t)); ++ __glibc_objsize0 (__s) / sizeof (wchar_t)); + } + return __wmemset_alias (__s, __c, __n); + } +@@ -151,8 +154,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias, + __fortify_function wchar_t * + __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + { +- if (__bos (__dest) != (size_t) -1) +- return __wcscpy_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t)); ++ if (__glibc_objsize (__dest) != (size_t) -1) ++ return __wcscpy_chk (__dest, __src, ++ __glibc_objsize (__dest) / sizeof (wchar_t)); + return __wcscpy_alias (__dest, __src); + } + +@@ -167,8 +171,9 @@ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias, + __fortify_function wchar_t * + __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + { +- if (__bos (__dest) != (size_t) -1) +- return __wcpcpy_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t)); ++ if (__glibc_objsize (__dest) != (size_t) -1) ++ return __wcpcpy_chk (__dest, __src, ++ __glibc_objsize (__dest) / sizeof (wchar_t)); + return __wcpcpy_alias (__dest, __src); + } + +@@ -191,14 +196,15 @@ __fortify_function wchar_t * + __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + size_t __n)) + { +- if (__bos (__dest) != (size_t) -1) ++ if (__glibc_objsize (__dest) != (size_t) -1) + { + if (!__builtin_constant_p (__n)) + return __wcsncpy_chk (__dest, __src, __n, +- __bos (__dest) / sizeof (wchar_t)); +- if (__n > __bos (__dest) / sizeof (wchar_t)) ++ __glibc_objsize (__dest) / sizeof (wchar_t)); ++ if (__n > __glibc_objsize (__dest) / sizeof (wchar_t)) + return __wcsncpy_chk_warn (__dest, __src, __n, +- __bos (__dest) / sizeof (wchar_t)); ++ (__glibc_objsize (__dest) ++ / sizeof (wchar_t))); + } + return __wcsncpy_alias (__dest, __src, __n); + } +@@ -222,14 +228,15 @@ __fortify_function wchar_t * + __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + size_t __n)) + { +- if (__bos (__dest) != (size_t) -1) ++ if (__glibc_objsize (__dest) != (size_t) -1) + { + if (!__builtin_constant_p (__n)) + return __wcpncpy_chk (__dest, __src, __n, +- __bos (__dest) / sizeof (wchar_t)); +- if (__n > __bos (__dest) / sizeof (wchar_t)) ++ __glibc_objsize (__dest) / sizeof (wchar_t)); ++ if (__n > __glibc_objsize (__dest) / sizeof (wchar_t)) + return __wcpncpy_chk_warn (__dest, __src, __n, +- __bos (__dest) / sizeof (wchar_t)); ++ (__glibc_objsize (__dest) ++ / sizeof (wchar_t))); + } + return __wcpncpy_alias (__dest, __src, __n); + } +@@ -245,8 +252,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscat_alias, + __fortify_function wchar_t * + __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + { +- if (__bos (__dest) != (size_t) -1) +- return __wcscat_chk (__dest, __src, __bos (__dest) / sizeof (wchar_t)); ++ if (__glibc_objsize (__dest) != (size_t) -1) ++ return __wcscat_chk (__dest, __src, ++ __glibc_objsize (__dest) / sizeof (wchar_t)); + return __wcscat_alias (__dest, __src); + } + +@@ -263,9 +271,9 @@ __fortify_function wchar_t * + __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + size_t __n)) + { +- if (__bos (__dest) != (size_t) -1) ++ if (__glibc_objsize (__dest) != (size_t) -1) + return __wcsncat_chk (__dest, __src, __n, +- __bos (__dest) / sizeof (wchar_t)); ++ __glibc_objsize (__dest) / sizeof (wchar_t)); + return __wcsncat_alias (__dest, __src, __n); + } + +@@ -285,18 +293,18 @@ __fortify_function int + __NTH (swprintf (wchar_t *__restrict __s, size_t __n, + const wchar_t *__restrict __fmt, ...)) + { +- if (__bos (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1) ++ if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1) + return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, +- __bos (__s) / sizeof (wchar_t), ++ __glibc_objsize (__s) / sizeof (wchar_t), + __fmt, __va_arg_pack ()); + return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ()); + } + #elif !defined __cplusplus + /* XXX We might want to have support in gcc for swprintf. */ + # define swprintf(s, n, ...) \ +- (__bos (s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1 \ ++ (__glibc_objsize (s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1 \ + ? __swprintf_chk (s, n, __USE_FORTIFY_LEVEL - 1, \ +- __bos (s) / sizeof (wchar_t), __VA_ARGS__) \ ++ __glibc_objsize (s) / sizeof (wchar_t), __VA_ARGS__) \ + : swprintf (s, n, __VA_ARGS__)) + #endif + +@@ -315,9 +323,10 @@ __fortify_function int + __NTH (vswprintf (wchar_t *__restrict __s, size_t __n, + const wchar_t *__restrict __fmt, __gnuc_va_list __ap)) + { +- if (__bos (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1) ++ if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1) + return __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, +- __bos (__s) / sizeof (wchar_t), __fmt, __ap); ++ __glibc_objsize (__s) / sizeof (wchar_t), __fmt, ++ __ap); + return __vswprintf_alias (__s, __n, __fmt, __ap); + } + +@@ -383,14 +392,15 @@ extern wchar_t *__REDIRECT (__fgetws_chk_warn, + __fortify_function __wur wchar_t * + fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + { +- if (__bos (__s) != (size_t) -1) ++ if (__glibc_objsize (__s) != (size_t) -1) + { + if (!__builtin_constant_p (__n) || __n <= 0) +- return __fgetws_chk (__s, __bos (__s) / sizeof (wchar_t), ++ return __fgetws_chk (__s, __glibc_objsize (__s) / sizeof (wchar_t), + __n, __stream); + +- if ((size_t) __n > __bos (__s) / sizeof (wchar_t)) +- return __fgetws_chk_warn (__s, __bos (__s) / sizeof (wchar_t), ++ if ((size_t) __n > __glibc_objsize (__s) / sizeof (wchar_t)) ++ return __fgetws_chk_warn (__s, ++ __glibc_objsize (__s) / sizeof (wchar_t), + __n, __stream); + } + return __fgetws_alias (__s, __n, __stream); +@@ -414,14 +424,17 @@ extern wchar_t *__REDIRECT (__fgetws_unlocked_chk_warn, + __fortify_function __wur wchar_t * + fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + { +- if (__bos (__s) != (size_t) -1) ++ if (__glibc_objsize (__s) != (size_t) -1) + { + if (!__builtin_constant_p (__n) || __n <= 0) +- return __fgetws_unlocked_chk (__s, __bos (__s) / sizeof (wchar_t), ++ return __fgetws_unlocked_chk (__s, ++ __glibc_objsize (__s) / sizeof (wchar_t), + __n, __stream); + +- if ((size_t) __n > __bos (__s) / sizeof (wchar_t)) +- return __fgetws_unlocked_chk_warn (__s, __bos (__s) / sizeof (wchar_t), ++ if ((size_t) __n > __glibc_objsize (__s) / sizeof (wchar_t)) ++ return __fgetws_unlocked_chk_warn (__s, ++ (__glibc_objsize (__s) ++ / sizeof (wchar_t)), + __n, __stream); + } + return __fgetws_unlocked_alias (__s, __n, __stream); +@@ -447,8 +460,9 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar, + #if defined MB_LEN_MAX && MB_LEN_MAX != __WCHAR_MB_LEN_MAX + # error "Assumed value of MB_LEN_MAX wrong" + #endif +- if (__bos (__s) != (size_t) -1 && __WCHAR_MB_LEN_MAX > __bos (__s)) +- return __wcrtomb_chk (__s, __wchar, __ps, __bos (__s)); ++ if (__glibc_objsize (__s) != (size_t) -1 ++ && __WCHAR_MB_LEN_MAX > __glibc_objsize (__s)) ++ return __wcrtomb_chk (__s, __wchar, __ps, __glibc_objsize (__s)); + return __wcrtomb_alias (__s, __wchar, __ps); + } + +@@ -474,15 +488,16 @@ __fortify_function size_t + __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + size_t __len, mbstate_t *__restrict __ps)) + { +- if (__bos (__dst) != (size_t) -1) ++ if (__glibc_objsize (__dst) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) + return __mbsrtowcs_chk (__dst, __src, __len, __ps, +- __bos (__dst) / sizeof (wchar_t)); ++ __glibc_objsize (__dst) / sizeof (wchar_t)); + +- if (__len > __bos (__dst) / sizeof (wchar_t)) ++ if (__len > __glibc_objsize (__dst) / sizeof (wchar_t)) + return __mbsrtowcs_chk_warn (__dst, __src, __len, __ps, +- __bos (__dst) / sizeof (wchar_t)); ++ (__glibc_objsize (__dst) ++ / sizeof (wchar_t))); + } + return __mbsrtowcs_alias (__dst, __src, __len, __ps); + } +@@ -508,13 +523,15 @@ __fortify_function size_t + __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + size_t __len, mbstate_t *__restrict __ps)) + { +- if (__bos (__dst) != (size_t) -1) ++ if (__glibc_objsize (__dst) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) +- return __wcsrtombs_chk (__dst, __src, __len, __ps, __bos (__dst)); ++ return __wcsrtombs_chk (__dst, __src, __len, __ps, ++ __glibc_objsize (__dst)); + +- if (__len > __bos (__dst)) +- return __wcsrtombs_chk_warn (__dst, __src, __len, __ps, __bos (__dst)); ++ if (__len > __glibc_objsize (__dst)) ++ return __wcsrtombs_chk_warn (__dst, __src, __len, __ps, ++ __glibc_objsize (__dst)); + } + return __wcsrtombs_alias (__dst, __src, __len, __ps); + } +@@ -542,15 +559,16 @@ __fortify_function size_t + __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + size_t __nmc, size_t __len, mbstate_t *__restrict __ps)) + { +- if (__bos (__dst) != (size_t) -1) ++ if (__glibc_objsize (__dst) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) + return __mbsnrtowcs_chk (__dst, __src, __nmc, __len, __ps, +- __bos (__dst) / sizeof (wchar_t)); ++ __glibc_objsize (__dst) / sizeof (wchar_t)); + +- if (__len > __bos (__dst) / sizeof (wchar_t)) ++ if (__len > __glibc_objsize (__dst) / sizeof (wchar_t)) + return __mbsnrtowcs_chk_warn (__dst, __src, __nmc, __len, __ps, +- __bos (__dst) / sizeof (wchar_t)); ++ (__glibc_objsize (__dst) ++ / sizeof (wchar_t))); + } + return __mbsnrtowcs_alias (__dst, __src, __nmc, __len, __ps); + } +@@ -578,15 +596,15 @@ __fortify_function size_t + __NTH (wcsnrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + size_t __nwc, size_t __len, mbstate_t *__restrict __ps)) + { +- if (__bos (__dst) != (size_t) -1) ++ if (__glibc_objsize (__dst) != (size_t) -1) + { + if (!__builtin_constant_p (__len)) + return __wcsnrtombs_chk (__dst, __src, __nwc, __len, __ps, +- __bos (__dst)); ++ __glibc_objsize (__dst)); + +- if (__len > __bos (__dst)) ++ if (__len > __glibc_objsize (__dst)) + return __wcsnrtombs_chk_warn (__dst, __src, __nwc, __len, __ps, +- __bos (__dst)); ++ __glibc_objsize (__dst)); + } + return __wcsnrtombs_alias (__dst, __src, __nwc, __len, __ps); + } diff --git a/SOURCES/glibc-rh2033684-6.patch b/SOURCES/glibc-rh2033684-6.patch new file mode 100644 index 0000000..b183d70 --- /dev/null +++ b/SOURCES/glibc-rh2033684-6.patch @@ -0,0 +1,1037 @@ +commit a643f60c53876be0d57b4b7373770e6cb356fd13 +Author: Siddhesh Poyarekar +Date: Wed Oct 20 18:12:41 2021 +0530 + + Make sure that the fortified function conditionals are constant + + In _FORTIFY_SOURCE=3, the size expression may be non-constant, + resulting in branches in the inline functions remaining intact and + causing a tiny overhead. Clang (and in future, gcc) make sure that + the -1 case is always safe, i.e. any comparison of the generated + expression with (size_t)-1 is always false so that bit is taken care + of. The rest is avoidable since we want the _chk variant whenever we + have a size expression and it's not -1. + + Rework the conditionals in a uniform way to clearly indicate two + conditions at compile time: + + - Either the size is unknown (-1) or we know at compile time that the + operation length is less than the object size. We can call the + original function in this case. It could be that either the length, + object size or both are non-constant, but the compiler, through + range analysis, is able to fold the *comparison* to a constant. + + - The size and length are known and the compiler can see at compile + time that operation length > object size. This is valid grounds for + a warning at compile time, followed by emitting the _chk variant. + + For everything else, emit the _chk variant. + + This simplifies most of the fortified function implementations and at + the same time, ensures that only one call from _chk or the regular + function is emitted. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Adhemerval Zanella + +diff --git a/io/bits/poll2.h b/io/bits/poll2.h +index f47fd9ad0945234f..6f4dae77e5e2d0d3 100644 +--- a/io/bits/poll2.h ++++ b/io/bits/poll2.h +@@ -35,16 +35,9 @@ extern int __REDIRECT (__poll_chk_warn, (struct pollfd *__fds, nfds_t __nfds, + __fortify_function int + poll (struct pollfd *__fds, nfds_t __nfds, int __timeout) + { +- if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1) +- { +- if (! __builtin_constant_p (__nfds)) +- return __poll_chk (__fds, __nfds, __timeout, __glibc_objsize (__fds)); +- else if (__glibc_objsize (__fds) / sizeof (*__fds) < __nfds) +- return __poll_chk_warn (__fds, __nfds, __timeout, +- __glibc_objsize (__fds)); +- } +- +- return __poll_alias (__fds, __nfds, __timeout); ++ return __glibc_fortify (poll, __nfds, sizeof (*__fds), ++ __glibc_objsize (__fds), ++ __fds, __nfds, __timeout); + } + + +@@ -66,17 +59,9 @@ __fortify_function int + ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout, + const __sigset_t *__ss) + { +- if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1) +- { +- if (! __builtin_constant_p (__nfds)) +- return __ppoll_chk (__fds, __nfds, __timeout, __ss, +- __glibc_objsize (__fds)); +- else if (__glibc_objsize (__fds) / sizeof (*__fds) < __nfds) +- return __ppoll_chk_warn (__fds, __nfds, __timeout, __ss, +- __glibc_objsize (__fds)); +- } +- +- return __ppoll_alias (__fds, __nfds, __timeout, __ss); ++ return __glibc_fortify (ppoll, __nfds, sizeof (*__fds), ++ __glibc_objsize (__fds), ++ __fds, __nfds, __timeout, __ss); + } + #endif + +diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h +index 2cd69f44cfadfc9f..4630fe0256b1a562 100644 +--- a/libio/bits/stdio2.h ++++ b/libio/bits/stdio2.h +@@ -256,15 +256,12 @@ extern char *__REDIRECT (__fgets_chk_warn, + __fortify_function __wur char * + fgets (char *__restrict __s, int __n, FILE *__restrict __stream) + { +- if (__glibc_objsize (__s) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n) || __n <= 0) +- return __fgets_chk (__s, __glibc_objsize (__s), __n, __stream); +- +- if ((size_t) __n > __glibc_objsize (__s)) +- return __fgets_chk_warn (__s, __glibc_objsize (__s), __n, __stream); +- } +- return __fgets_alias (__s, __n, __stream); ++ size_t sz = __glibc_objsize (__s); ++ if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz)) ++ return __fgets_alias (__s, __n, __stream); ++ if (__glibc_unsafe_len (__n, sizeof (char), sz)) ++ return __fgets_chk_warn (__s, sz, __n, __stream); ++ return __fgets_chk (__s, sz, __n, __stream); + } + + extern size_t __fread_chk (void *__restrict __ptr, size_t __ptrlen, +@@ -286,19 +283,12 @@ __fortify_function __wur size_t + fread (void *__restrict __ptr, size_t __size, size_t __n, + FILE *__restrict __stream) + { +- if (__glibc_objsize0 (__ptr) != (size_t) -1) +- { +- if (!__builtin_constant_p (__size) +- || !__builtin_constant_p (__n) +- || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2))) +- return __fread_chk (__ptr, __glibc_objsize0 (__ptr), __size, __n, +- __stream); +- +- if (__size * __n > __glibc_objsize0 (__ptr)) +- return __fread_chk_warn (__ptr, __glibc_objsize0 (__ptr), __size, __n, +- __stream); +- } +- return __fread_alias (__ptr, __size, __n, __stream); ++ size_t sz = __glibc_objsize0 (__ptr); ++ if (__glibc_safe_or_unknown_len (__n, __size, sz)) ++ return __fread_alias (__ptr, __size, __n, __stream); ++ if (__glibc_unsafe_len (__n, __size, sz)) ++ return __fread_chk_warn (__ptr, sz, __size, __n, __stream); ++ return __fread_chk (__ptr, sz, __size, __n, __stream); + } + + #ifdef __USE_GNU +@@ -316,17 +306,12 @@ extern char *__REDIRECT (__fgets_unlocked_chk_warn, + __fortify_function __wur char * + fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream) + { +- if (__glibc_objsize (__s) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n) || __n <= 0) +- return __fgets_unlocked_chk (__s, __glibc_objsize (__s), __n, +- __stream); +- +- if ((size_t) __n > __glibc_objsize (__s)) +- return __fgets_unlocked_chk_warn (__s, __glibc_objsize (__s), __n, +- __stream); +- } +- return __fgets_unlocked_alias (__s, __n, __stream); ++ size_t sz = __glibc_objsize (__s); ++ if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz)) ++ return __fgets_unlocked_alias (__s, __n, __stream); ++ if (__glibc_unsafe_len (__n, sizeof (char), sz)) ++ return __fgets_unlocked_chk_warn (__s, sz, __n, __stream); ++ return __fgets_unlocked_chk (__s, sz, __n, __stream); + } + #endif + +@@ -351,41 +336,36 @@ __fortify_function __wur size_t + fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n, + FILE *__restrict __stream) + { +- if (__glibc_objsize0 (__ptr) != (size_t) -1) ++ size_t sz = __glibc_objsize0 (__ptr); ++ if (__glibc_safe_or_unknown_len (__n, __size, sz)) + { +- if (!__builtin_constant_p (__size) +- || !__builtin_constant_p (__n) +- || (__size | __n) >= (((size_t) 1) << (8 * sizeof (size_t) / 2))) +- return __fread_unlocked_chk (__ptr, __glibc_objsize0 (__ptr), __size, +- __n, __stream); +- +- if (__size * __n > __glibc_objsize0 (__ptr)) +- return __fread_unlocked_chk_warn (__ptr, __glibc_objsize0 (__ptr), +- __size, __n, __stream); +- } +- + # ifdef __USE_EXTERN_INLINES +- if (__builtin_constant_p (__size) +- && __builtin_constant_p (__n) +- && (__size | __n) < (((size_t) 1) << (8 * sizeof (size_t) / 2)) +- && __size * __n <= 8) +- { +- size_t __cnt = __size * __n; +- char *__cptr = (char *) __ptr; +- if (__cnt == 0) +- return 0; +- +- for (; __cnt > 0; --__cnt) ++ if (__builtin_constant_p (__size) ++ && __builtin_constant_p (__n) ++ && (__size | __n) < (((size_t) 1) << (8 * sizeof (size_t) / 2)) ++ && __size * __n <= 8) + { +- int __c = getc_unlocked (__stream); +- if (__c == EOF) +- break; +- *__cptr++ = __c; ++ size_t __cnt = __size * __n; ++ char *__cptr = (char *) __ptr; ++ if (__cnt == 0) ++ return 0; ++ ++ for (; __cnt > 0; --__cnt) ++ { ++ int __c = getc_unlocked (__stream); ++ if (__c == EOF) ++ break; ++ *__cptr++ = __c; ++ } ++ return (__cptr - (char *) __ptr) / __size; + } +- return (__cptr - (char *) __ptr) / __size; +- } + # endif +- return __fread_unlocked_alias (__ptr, __size, __n, __stream); ++ return __fread_unlocked_alias (__ptr, __size, __n, __stream); ++ } ++ if (__glibc_unsafe_len (__n, __size, sz)) ++ return __fread_unlocked_chk_warn (__ptr, sz, __size, __n, __stream); ++ return __fread_unlocked_chk (__ptr, sz, __size, __n, __stream); ++ + } + #endif + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 1e39307b0ebcf38f..17b84a2e6c69d961 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -132,6 +132,53 @@ + # define __glibc_objsize(__o) __bos (__o) + #endif + ++/* Compile time conditions to choose between the regular, _chk and _chk_warn ++ variants. These conditions should get evaluated to constant and optimized ++ away. */ ++ ++#define __glibc_safe_len_cond(__l, __s, __osz) ((__l) <= (__osz) / (__s)) ++#define __glibc_unsigned_or_positive(__l) \ ++ ((__typeof (__l)) 0 < (__typeof (__l)) -1 \ ++ || (__builtin_constant_p (__l) && (__l) > 0)) ++ ++/* Length is known to be safe at compile time if the __L * __S <= __OBJSZ ++ condition can be folded to a constant and if it is true. The -1 check is ++ redundant because since it implies that __glibc_safe_len_cond is true. */ ++#define __glibc_safe_or_unknown_len(__l, __s, __osz) \ ++ (__glibc_unsigned_or_positive (__l) \ ++ && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ ++ __s, __osz)) \ ++ && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz)) ++ ++/* Conversely, we know at compile time that the length is safe if the ++ __L * __S <= __OBJSZ condition can be folded to a constant and if it is ++ false. */ ++#define __glibc_unsafe_len(__l, __s, __osz) \ ++ (__glibc_unsigned_or_positive (__l) \ ++ && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ ++ __s, __osz)) \ ++ && !__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz)) ++ ++/* Fortify function f. __f_alias, __f_chk and __f_chk_warn must be ++ declared. */ ++ ++#define __glibc_fortify(f, __l, __s, __osz, ...) \ ++ (__glibc_safe_or_unknown_len (__l, __s, __osz) \ ++ ? __ ## f ## _alias (__VA_ARGS__) \ ++ : (__glibc_unsafe_len (__l, __s, __osz) \ ++ ? __ ## f ## _chk_warn (__VA_ARGS__, __osz) \ ++ : __ ## f ## _chk (__VA_ARGS__, __osz))) \ ++ ++/* Fortify function f, where object size argument passed to f is the number of ++ elements and not total size. */ ++ ++#define __glibc_fortify_n(f, __l, __s, __osz, ...) \ ++ (__glibc_safe_or_unknown_len (__l, __s, __osz) \ ++ ? __ ## f ## _alias (__VA_ARGS__) \ ++ : (__glibc_unsafe_len (__l, __s, __osz) \ ++ ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \ ++ : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \ ++ + #if __GNUC_PREREQ (4,3) + # define __warndecl(name, msg) \ + extern void name (void) __attribute__((__warning__ (msg))) +diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h +index a0c4dcfe9c61a7b8..a456d1723547db70 100644 +--- a/posix/bits/unistd.h ++++ b/posix/bits/unistd.h +@@ -33,16 +33,9 @@ extern ssize_t __REDIRECT (__read_chk_warn, + __fortify_function __wur ssize_t + read (int __fd, void *__buf, size_t __nbytes) + { +- if (__glibc_objsize0 (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__nbytes)) +- return __read_chk (__fd, __buf, __nbytes, __glibc_objsize0 (__buf)); +- +- if (__nbytes > __glibc_objsize0 (__buf)) +- return __read_chk_warn (__fd, __buf, __nbytes, +- __glibc_objsize0 (__buf)); +- } +- return __read_alias (__fd, __buf, __nbytes); ++ return __glibc_fortify (read, __nbytes, sizeof (char), ++ __glibc_objsize0 (__buf), ++ __fd, __buf, __nbytes); + } + + #ifdef __USE_UNIX98 +@@ -72,34 +65,17 @@ extern ssize_t __REDIRECT (__pread64_chk_warn, + __fortify_function __wur ssize_t + pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset) + { +- if (__glibc_objsize0 (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__nbytes)) +- return __pread_chk (__fd, __buf, __nbytes, __offset, +- __glibc_objsize0 (__buf)); +- +- if ( __nbytes > __glibc_objsize0 (__buf)) +- return __pread_chk_warn (__fd, __buf, __nbytes, __offset, +- __glibc_objsize0 (__buf)); +- } +- return __pread_alias (__fd, __buf, __nbytes, __offset); ++ return __glibc_fortify (pread, __nbytes, sizeof (char), ++ __glibc_objsize0 (__buf), ++ __fd, __buf, __nbytes, __offset); + } + # else + __fortify_function __wur ssize_t + pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) + { +- if (__glibc_objsize0 (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__nbytes)) +- return __pread64_chk (__fd, __buf, __nbytes, __offset, +- __glibc_objsize0 (__buf)); +- +- if ( __nbytes > __glibc_objsize0 (__buf)) +- return __pread64_chk_warn (__fd, __buf, __nbytes, __offset, +- __glibc_objsize0 (__buf)); +- } +- +- return __pread64_alias (__fd, __buf, __nbytes, __offset); ++ return __glibc_fortify (pread64, __nbytes, sizeof (char), ++ __glibc_objsize0 (__buf), ++ __fd, __buf, __nbytes, __offset); + } + # endif + +@@ -107,18 +83,9 @@ pread (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) + __fortify_function __wur ssize_t + pread64 (int __fd, void *__buf, size_t __nbytes, __off64_t __offset) + { +- if (__glibc_objsize0 (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__nbytes)) +- return __pread64_chk (__fd, __buf, __nbytes, __offset, +- __glibc_objsize0 (__buf)); +- +- if ( __nbytes > __glibc_objsize0 (__buf)) +- return __pread64_chk_warn (__fd, __buf, __nbytes, __offset, +- __glibc_objsize0 (__buf)); +- } +- +- return __pread64_alias (__fd, __buf, __nbytes, __offset); ++ return __glibc_fortify (pread64, __nbytes, sizeof (char), ++ __glibc_objsize0 (__buf), ++ __fd, __buf, __nbytes, __offset); + } + # endif + #endif +@@ -143,16 +110,9 @@ __fortify_function __nonnull ((1, 2)) __wur ssize_t + __NTH (readlink (const char *__restrict __path, char *__restrict __buf, + size_t __len)) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __readlink_chk (__path, __buf, __len, __glibc_objsize (__buf)); +- +- if ( __len > __glibc_objsize (__buf)) +- return __readlink_chk_warn (__path, __buf, __len, +- __glibc_objsize (__buf)); +- } +- return __readlink_alias (__path, __buf, __len); ++ return __glibc_fortify (readlink, __len, sizeof (char), ++ __glibc_objsize (__buf), ++ __path, __buf, __len); + } + #endif + +@@ -178,17 +138,9 @@ __fortify_function __nonnull ((2, 3)) __wur ssize_t + __NTH (readlinkat (int __fd, const char *__restrict __path, + char *__restrict __buf, size_t __len)) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __readlinkat_chk (__fd, __path, __buf, __len, +- __glibc_objsize (__buf)); +- +- if (__len > __glibc_objsize (__buf)) +- return __readlinkat_chk_warn (__fd, __path, __buf, __len, +- __glibc_objsize (__buf)); +- } +- return __readlinkat_alias (__fd, __path, __buf, __len); ++ return __glibc_fortify (readlinkat, __len, sizeof (char), ++ __glibc_objsize (__buf), ++ __fd, __path, __buf, __len); + } + #endif + +@@ -205,15 +157,9 @@ extern char *__REDIRECT_NTH (__getcwd_chk_warn, + __fortify_function __wur char * + __NTH (getcwd (char *__buf, size_t __size)) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__size)) +- return __getcwd_chk (__buf, __size, __glibc_objsize (__buf)); +- +- if (__size > __glibc_objsize (__buf)) +- return __getcwd_chk_warn (__buf, __size, __glibc_objsize (__buf)); +- } +- return __getcwd_alias (__buf, __size); ++ return __glibc_fortify (getcwd, __size, sizeof (char), ++ __glibc_objsize (__buf), ++ __buf, __size); + } + + #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED +@@ -245,16 +191,9 @@ extern size_t __REDIRECT_NTH (__confstr_chk_warn, + __fortify_function size_t + __NTH (confstr (int __name, char *__buf, size_t __len)) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __confstr_chk (__name, __buf, __len, __glibc_objsize (__buf)); +- +- if (__glibc_objsize (__buf) < __len) +- return __confstr_chk_warn (__name, __buf, __len, +- __glibc_objsize (__buf)); +- } +- return __confstr_alias (__name, __buf, __len); ++ return __glibc_fortify (confstr, __len, sizeof (char), ++ __glibc_objsize (__buf), ++ __name, __buf, __len); + } + + +@@ -271,15 +210,9 @@ extern int __REDIRECT_NTH (__getgroups_chk_warn, + __fortify_function int + __NTH (getgroups (int __size, __gid_t __list[])) + { +- if (__glibc_objsize (__list) != (size_t) -1) +- { +- if (!__builtin_constant_p (__size) || __size < 0) +- return __getgroups_chk (__size, __list, __glibc_objsize (__list)); +- +- if (__size * sizeof (__gid_t) > __glibc_objsize (__list)) +- return __getgroups_chk_warn (__size, __list, __glibc_objsize (__list)); +- } +- return __getgroups_alias (__size, __list); ++ return __glibc_fortify (getgroups, __size, sizeof (__gid_t), ++ __glibc_objsize (__list), ++ __size, __list); + } + + +@@ -297,17 +230,9 @@ extern int __REDIRECT_NTH (__ttyname_r_chk_warn, + __fortify_function int + __NTH (ttyname_r (int __fd, char *__buf, size_t __buflen)) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__buflen)) +- return __ttyname_r_chk (__fd, __buf, __buflen, +- __glibc_objsize (__buf)); +- +- if (__buflen > __glibc_objsize (__buf)) +- return __ttyname_r_chk_warn (__fd, __buf, __buflen, +- __glibc_objsize (__buf)); +- } +- return __ttyname_r_alias (__fd, __buf, __buflen); ++ return __glibc_fortify (ttyname_r, __buflen, sizeof (char), ++ __glibc_objsize (__buf), ++ __fd, __buf, __buflen); + } + + +@@ -325,16 +250,9 @@ extern int __REDIRECT (__getlogin_r_chk_warn, + __fortify_function int + getlogin_r (char *__buf, size_t __buflen) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__buflen)) +- return __getlogin_r_chk (__buf, __buflen, __glibc_objsize (__buf)); +- +- if (__buflen > __glibc_objsize (__buf)) +- return __getlogin_r_chk_warn (__buf, __buflen, +- __glibc_objsize (__buf)); +- } +- return __getlogin_r_alias (__buf, __buflen); ++ return __glibc_fortify (getlogin_r, __buflen, sizeof (char), ++ __glibc_objsize (__buf), ++ __buf, __buflen); + } + #endif + +@@ -353,16 +271,9 @@ extern int __REDIRECT_NTH (__gethostname_chk_warn, + __fortify_function int + __NTH (gethostname (char *__buf, size_t __buflen)) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__buflen)) +- return __gethostname_chk (__buf, __buflen, __glibc_objsize (__buf)); +- +- if (__buflen > __glibc_objsize (__buf)) +- return __gethostname_chk_warn (__buf, __buflen, +- __glibc_objsize (__buf)); +- } +- return __gethostname_alias (__buf, __buflen); ++ return __glibc_fortify (gethostname, __buflen, sizeof (char), ++ __glibc_objsize (__buf), ++ __buf, __buflen); + } + #endif + +@@ -383,15 +294,8 @@ extern int __REDIRECT_NTH (__getdomainname_chk_warn, + __fortify_function int + __NTH (getdomainname (char *__buf, size_t __buflen)) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__buflen)) +- return __getdomainname_chk (__buf, __buflen, __glibc_objsize (__buf)); +- +- if (__buflen > __glibc_objsize (__buf)) +- return __getdomainname_chk_warn (__buf, __buflen, +- __glibc_objsize (__buf)); +- } +- return __getdomainname_alias (__buf, __buflen); ++ return __glibc_fortify (getdomainname, __buflen, sizeof (char), ++ __glibc_objsize (__buf), ++ __buf, __buflen); + } + #endif +diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h +index 729e5a4cc1f4cb92..68fe5435b3b29c2a 100644 +--- a/socket/bits/socket2.h ++++ b/socket/bits/socket2.h +@@ -33,17 +33,12 @@ extern ssize_t __REDIRECT (__recv_chk_warn, + __fortify_function ssize_t + recv (int __fd, void *__buf, size_t __n, int __flags) + { +- if (__glibc_objsize0 (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n)) +- return __recv_chk (__fd, __buf, __n, __glibc_objsize0 (__buf), +- __flags); +- +- if (__n > __glibc_objsize0 (__buf)) +- return __recv_chk_warn (__fd, __buf, __n, __glibc_objsize0 (__buf), +- __flags); +- } +- return __recv_alias (__fd, __buf, __n, __flags); ++ size_t sz = __glibc_objsize0 (__buf); ++ if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz)) ++ return __recv_alias (__fd, __buf, __n, __flags); ++ if (__glibc_unsafe_len (__n, sizeof (char), sz)) ++ return __recv_chk_warn (__fd, __buf, __n, sz, __flags); ++ return __recv_chk (__fd, __buf, __n, sz, __flags); + } + + extern ssize_t __recvfrom_chk (int __fd, void *__restrict __buf, size_t __n, +@@ -66,14 +61,11 @@ __fortify_function ssize_t + recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags, + __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len) + { +- if (__glibc_objsize0 (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n)) +- return __recvfrom_chk (__fd, __buf, __n, __glibc_objsize0 (__buf), +- __flags, __addr, __addr_len); +- if (__n > __glibc_objsize0 (__buf)) +- return __recvfrom_chk_warn (__fd, __buf, __n, __glibc_objsize0 (__buf), +- __flags, __addr, __addr_len); +- } +- return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len); ++ size_t sz = __glibc_objsize0 (__buf); ++ if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz)) ++ return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len); ++ if (__glibc_unsafe_len (__n, sizeof (char), sz)) ++ return __recvfrom_chk_warn (__fd, __buf, __n, sz, __flags, __addr, ++ __addr_len); ++ return __recvfrom_chk (__fd, __buf, __n, sz, __flags, __addr, __addr_len); + } +diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h +index 5e4114ded33f2033..7ea364a276497720 100644 +--- a/stdlib/bits/stdlib.h ++++ b/stdlib/bits/stdlib.h +@@ -36,17 +36,16 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn, + __fortify_function __wur char * + __NTH (realpath (const char *__restrict __name, char *__restrict __resolved)) + { +- if (__glibc_objsize (__resolved) != (size_t) -1) +- { ++ size_t sz = __glibc_objsize (__resolved); ++ ++ if (sz == (size_t) -1) ++ return __realpath_alias (__name, __resolved); ++ + #if defined _LIBC_LIMITS_H_ && defined PATH_MAX +- if (__glibc_objsize (__resolved) < PATH_MAX) +- return __realpath_chk_warn (__name, __resolved, +- __glibc_objsize (__resolved)); ++ if (__glibc_unsafe_len (sz, sizeof (char), PATH_MAX)) ++ return __realpath_chk_warn (__name, __resolved, sz); + #endif +- return __realpath_chk (__name, __resolved, __glibc_objsize (__resolved)); +- } +- +- return __realpath_alias (__name, __resolved); ++ return __realpath_chk (__name, __resolved, sz); + } + + +@@ -64,16 +63,9 @@ extern int __REDIRECT_NTH (__ptsname_r_chk_warn, + __fortify_function int + __NTH (ptsname_r (int __fd, char *__buf, size_t __buflen)) + { +- if (__glibc_objsize (__buf) != (size_t) -1) +- { +- if (!__builtin_constant_p (__buflen)) +- return __ptsname_r_chk (__fd, __buf, __buflen, +- __glibc_objsize (__buf)); +- if (__buflen > __glibc_objsize (__buf)) +- return __ptsname_r_chk_warn (__fd, __buf, __buflen, +- __glibc_objsize (__buf)); +- } +- return __ptsname_r_alias (__fd, __buf, __buflen); ++ return __glibc_fortify (ptsname_r, __buflen, sizeof (char), ++ __glibc_objsize (__buf), ++ __fd, __buf, __buflen); + } + + +@@ -117,18 +109,9 @@ __fortify_function size_t + __NTH (mbstowcs (wchar_t *__restrict __dst, const char *__restrict __src, + size_t __len)) + { +- if (__glibc_objsize (__dst) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __mbstowcs_chk (__dst, __src, __len, +- __glibc_objsize (__dst) / sizeof (wchar_t)); +- +- if (__len > __glibc_objsize (__dst) / sizeof (wchar_t)) +- return __mbstowcs_chk_warn (__dst, __src, __len, +- (__glibc_objsize (__dst) +- / sizeof (wchar_t))); +- } +- return __mbstowcs_alias (__dst, __src, __len); ++ return __glibc_fortify_n (mbstowcs, __len, sizeof (wchar_t), ++ __glibc_objsize (__dst), ++ __dst, __src, __len); + } + + +@@ -149,13 +132,7 @@ __fortify_function size_t + __NTH (wcstombs (char *__restrict __dst, const wchar_t *__restrict __src, + size_t __len)) + { +- if (__glibc_objsize (__dst) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __wcstombs_chk (__dst, __src, __len, __glibc_objsize (__dst)); +- if (__len > __glibc_objsize (__dst)) +- return __wcstombs_chk_warn (__dst, __src, __len, +- __glibc_objsize (__dst)); +- } +- return __wcstombs_alias (__dst, __src, __len); ++ return __glibc_fortify (wcstombs, __len, sizeof (char), ++ __glibc_objsize (__dst), ++ __dst, __src, __len); + } +diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h +index 838ba877ee4b4afe..f82bba481981e4fb 100644 +--- a/wcsmbs/bits/wchar2.h ++++ b/wcsmbs/bits/wchar2.h +@@ -39,17 +39,9 @@ __fortify_function wchar_t * + __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + size_t __n)) + { +- if (__glibc_objsize0 (__s1) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n)) +- return __wmemcpy_chk (__s1, __s2, __n, +- __glibc_objsize0 (__s1) / sizeof (wchar_t)); +- +- if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t)) +- return __wmemcpy_chk_warn (__s1, __s2, __n, +- __glibc_objsize0 (__s1) / sizeof (wchar_t)); +- } +- return __wmemcpy_alias (__s1, __s2, __n); ++ return __glibc_fortify_n (wmemcpy, __n, sizeof (wchar_t), ++ __glibc_objsize0 (__s1), ++ __s1, __s2, __n); + } + + +@@ -67,18 +59,9 @@ extern wchar_t *__REDIRECT_NTH (__wmemmove_chk_warn, + __fortify_function wchar_t * + __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n)) + { +- if (__glibc_objsize0 (__s1) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n)) +- return __wmemmove_chk (__s1, __s2, __n, +- __glibc_objsize0 (__s1) / sizeof (wchar_t)); +- +- if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t)) +- return __wmemmove_chk_warn (__s1, __s2, __n, +- (__glibc_objsize0 (__s1) +- / sizeof (wchar_t))); +- } +- return __wmemmove_alias (__s1, __s2, __n); ++ return __glibc_fortify_n (wmemmove, __n, sizeof (wchar_t), ++ __glibc_objsize0 (__s1), ++ __s1, __s2, __n); + } + + +@@ -101,18 +84,9 @@ __fortify_function wchar_t * + __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + size_t __n)) + { +- if (__glibc_objsize0 (__s1) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n)) +- return __wmempcpy_chk (__s1, __s2, __n, +- __glibc_objsize0 (__s1) / sizeof (wchar_t)); +- +- if (__n > __glibc_objsize0 (__s1) / sizeof (wchar_t)) +- return __wmempcpy_chk_warn (__s1, __s2, __n, +- (__glibc_objsize0 (__s1) +- / sizeof (wchar_t))); +- } +- return __wmempcpy_alias (__s1, __s2, __n); ++ return __glibc_fortify_n (wmempcpy, __n, sizeof (wchar_t), ++ __glibc_objsize0 (__s1), ++ __s1, __s2, __n); + } + #endif + +@@ -130,17 +104,9 @@ extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn, + __fortify_function wchar_t * + __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n)) + { +- if (__glibc_objsize0 (__s) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n)) +- return __wmemset_chk (__s, __c, __n, +- __glibc_objsize0 (__s) / sizeof (wchar_t)); +- +- if (__n > __glibc_objsize0 (__s) / sizeof (wchar_t)) +- return __wmemset_chk_warn (__s, __c, __n, +- __glibc_objsize0 (__s) / sizeof (wchar_t)); +- } +- return __wmemset_alias (__s, __c, __n); ++ return __glibc_fortify_n (wmemset, __n, sizeof (wchar_t), ++ __glibc_objsize0 (__s), ++ __s, __c, __n); + } + + +@@ -154,9 +120,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias, + __fortify_function wchar_t * + __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + { +- if (__glibc_objsize (__dest) != (size_t) -1) +- return __wcscpy_chk (__dest, __src, +- __glibc_objsize (__dest) / sizeof (wchar_t)); ++ size_t sz = __glibc_objsize (__dest); ++ if (sz != (size_t) -1) ++ return __wcscpy_chk (__dest, __src, sz / sizeof (wchar_t)); + return __wcscpy_alias (__dest, __src); + } + +@@ -171,9 +137,9 @@ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias, + __fortify_function wchar_t * + __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + { +- if (__glibc_objsize (__dest) != (size_t) -1) +- return __wcpcpy_chk (__dest, __src, +- __glibc_objsize (__dest) / sizeof (wchar_t)); ++ size_t sz = __glibc_objsize (__dest); ++ if (sz != (size_t) -1) ++ return __wcpcpy_chk (__dest, __src, sz / sizeof (wchar_t)); + return __wcpcpy_alias (__dest, __src); + } + +@@ -196,17 +162,9 @@ __fortify_function wchar_t * + __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + size_t __n)) + { +- if (__glibc_objsize (__dest) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n)) +- return __wcsncpy_chk (__dest, __src, __n, +- __glibc_objsize (__dest) / sizeof (wchar_t)); +- if (__n > __glibc_objsize (__dest) / sizeof (wchar_t)) +- return __wcsncpy_chk_warn (__dest, __src, __n, +- (__glibc_objsize (__dest) +- / sizeof (wchar_t))); +- } +- return __wcsncpy_alias (__dest, __src, __n); ++ return __glibc_fortify_n (wcsncpy, __n, sizeof (wchar_t), ++ __glibc_objsize (__dest), ++ __dest, __src, __n); + } + + +@@ -228,17 +186,9 @@ __fortify_function wchar_t * + __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + size_t __n)) + { +- if (__glibc_objsize (__dest) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n)) +- return __wcpncpy_chk (__dest, __src, __n, +- __glibc_objsize (__dest) / sizeof (wchar_t)); +- if (__n > __glibc_objsize (__dest) / sizeof (wchar_t)) +- return __wcpncpy_chk_warn (__dest, __src, __n, +- (__glibc_objsize (__dest) +- / sizeof (wchar_t))); +- } +- return __wcpncpy_alias (__dest, __src, __n); ++ return __glibc_fortify_n (wcpncpy, __n, sizeof (wchar_t), ++ __glibc_objsize (__dest), ++ __dest, __src, __n); + } + + +@@ -252,9 +202,9 @@ extern wchar_t *__REDIRECT_NTH (__wcscat_alias, + __fortify_function wchar_t * + __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + { +- if (__glibc_objsize (__dest) != (size_t) -1) +- return __wcscat_chk (__dest, __src, +- __glibc_objsize (__dest) / sizeof (wchar_t)); ++ size_t sz = __glibc_objsize (__dest); ++ if (sz != (size_t) -1) ++ return __wcscat_chk (__dest, __src, sz / sizeof (wchar_t)); + return __wcscat_alias (__dest, __src); + } + +@@ -271,9 +221,9 @@ __fortify_function wchar_t * + __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + size_t __n)) + { +- if (__glibc_objsize (__dest) != (size_t) -1) +- return __wcsncat_chk (__dest, __src, __n, +- __glibc_objsize (__dest) / sizeof (wchar_t)); ++ size_t sz = __glibc_objsize (__dest); ++ if (sz != (size_t) -1) ++ return __wcsncat_chk (__dest, __src, __n, sz / sizeof (wchar_t)); + return __wcsncat_alias (__dest, __src, __n); + } + +@@ -293,10 +243,10 @@ __fortify_function int + __NTH (swprintf (wchar_t *__restrict __s, size_t __n, + const wchar_t *__restrict __fmt, ...)) + { +- if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1) ++ size_t sz = __glibc_objsize (__s); ++ if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1) + return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, +- __glibc_objsize (__s) / sizeof (wchar_t), +- __fmt, __va_arg_pack ()); ++ sz / sizeof (wchar_t), __fmt, __va_arg_pack ()); + return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ()); + } + #elif !defined __cplusplus +@@ -323,10 +273,10 @@ __fortify_function int + __NTH (vswprintf (wchar_t *__restrict __s, size_t __n, + const wchar_t *__restrict __fmt, __gnuc_va_list __ap)) + { +- if (__glibc_objsize (__s) != (size_t) -1 || __USE_FORTIFY_LEVEL > 1) ++ size_t sz = __glibc_objsize (__s); ++ if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1) + return __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1, +- __glibc_objsize (__s) / sizeof (wchar_t), __fmt, +- __ap); ++ sz / sizeof (wchar_t), __fmt, __ap); + return __vswprintf_alias (__s, __n, __fmt, __ap); + } + +@@ -392,18 +342,12 @@ extern wchar_t *__REDIRECT (__fgetws_chk_warn, + __fortify_function __wur wchar_t * + fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + { +- if (__glibc_objsize (__s) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n) || __n <= 0) +- return __fgetws_chk (__s, __glibc_objsize (__s) / sizeof (wchar_t), +- __n, __stream); +- +- if ((size_t) __n > __glibc_objsize (__s) / sizeof (wchar_t)) +- return __fgetws_chk_warn (__s, +- __glibc_objsize (__s) / sizeof (wchar_t), +- __n, __stream); +- } +- return __fgetws_alias (__s, __n, __stream); ++ size_t sz = __glibc_objsize (__s); ++ if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz)) ++ return __fgetws_alias (__s, __n, __stream); ++ if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz)) ++ return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream); ++ return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream); + } + + #ifdef __USE_GNU +@@ -424,20 +368,13 @@ extern wchar_t *__REDIRECT (__fgetws_unlocked_chk_warn, + __fortify_function __wur wchar_t * + fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + { +- if (__glibc_objsize (__s) != (size_t) -1) +- { +- if (!__builtin_constant_p (__n) || __n <= 0) +- return __fgetws_unlocked_chk (__s, +- __glibc_objsize (__s) / sizeof (wchar_t), +- __n, __stream); +- +- if ((size_t) __n > __glibc_objsize (__s) / sizeof (wchar_t)) +- return __fgetws_unlocked_chk_warn (__s, +- (__glibc_objsize (__s) +- / sizeof (wchar_t)), +- __n, __stream); +- } +- return __fgetws_unlocked_alias (__s, __n, __stream); ++ size_t sz = __glibc_objsize (__s); ++ if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz)) ++ return __fgetws_unlocked_alias (__s, __n, __stream); ++ if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz)) ++ return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n, ++ __stream); ++ return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream); + } + #endif + +@@ -488,18 +425,9 @@ __fortify_function size_t + __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + size_t __len, mbstate_t *__restrict __ps)) + { +- if (__glibc_objsize (__dst) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __mbsrtowcs_chk (__dst, __src, __len, __ps, +- __glibc_objsize (__dst) / sizeof (wchar_t)); +- +- if (__len > __glibc_objsize (__dst) / sizeof (wchar_t)) +- return __mbsrtowcs_chk_warn (__dst, __src, __len, __ps, +- (__glibc_objsize (__dst) +- / sizeof (wchar_t))); +- } +- return __mbsrtowcs_alias (__dst, __src, __len, __ps); ++ return __glibc_fortify_n (mbsrtowcs, __len, sizeof (wchar_t), ++ __glibc_objsize (__dst), ++ __dst, __src, __len, __ps); + } + + +@@ -523,17 +451,9 @@ __fortify_function size_t + __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + size_t __len, mbstate_t *__restrict __ps)) + { +- if (__glibc_objsize (__dst) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __wcsrtombs_chk (__dst, __src, __len, __ps, +- __glibc_objsize (__dst)); +- +- if (__len > __glibc_objsize (__dst)) +- return __wcsrtombs_chk_warn (__dst, __src, __len, __ps, +- __glibc_objsize (__dst)); +- } +- return __wcsrtombs_alias (__dst, __src, __len, __ps); ++ return __glibc_fortify (wcsrtombs, __len, sizeof (char), ++ __glibc_objsize (__dst), ++ __dst, __src, __len, __ps); + } + + +@@ -559,18 +479,9 @@ __fortify_function size_t + __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + size_t __nmc, size_t __len, mbstate_t *__restrict __ps)) + { +- if (__glibc_objsize (__dst) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __mbsnrtowcs_chk (__dst, __src, __nmc, __len, __ps, +- __glibc_objsize (__dst) / sizeof (wchar_t)); +- +- if (__len > __glibc_objsize (__dst) / sizeof (wchar_t)) +- return __mbsnrtowcs_chk_warn (__dst, __src, __nmc, __len, __ps, +- (__glibc_objsize (__dst) +- / sizeof (wchar_t))); +- } +- return __mbsnrtowcs_alias (__dst, __src, __nmc, __len, __ps); ++ return __glibc_fortify_n (mbsnrtowcs, __len, sizeof (wchar_t), ++ __glibc_objsize (__dst), ++ __dst, __src, __nmc, __len, __ps); + } + + +@@ -596,16 +507,8 @@ __fortify_function size_t + __NTH (wcsnrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + size_t __nwc, size_t __len, mbstate_t *__restrict __ps)) + { +- if (__glibc_objsize (__dst) != (size_t) -1) +- { +- if (!__builtin_constant_p (__len)) +- return __wcsnrtombs_chk (__dst, __src, __nwc, __len, __ps, +- __glibc_objsize (__dst)); +- +- if (__len > __glibc_objsize (__dst)) +- return __wcsnrtombs_chk_warn (__dst, __src, __nwc, __len, __ps, +- __glibc_objsize (__dst)); +- } +- return __wcsnrtombs_alias (__dst, __src, __nwc, __len, __ps); ++ return __glibc_fortify (wcsnrtombs, __len, sizeof (char), ++ __glibc_objsize (__dst), ++ __dst, __src, __nwc, __len, __ps); + } + #endif diff --git a/SOURCES/glibc-rh2033684-7.patch b/SOURCES/glibc-rh2033684-7.patch new file mode 100644 index 0000000..7cb18a6 --- /dev/null +++ b/SOURCES/glibc-rh2033684-7.patch @@ -0,0 +1,43 @@ +commit fadf75c370494da6a02274ebe79e45b2f22ebbd0 +Author: Florian Weimer +Date: Mon Feb 10 14:37:10 2020 +0100 + + debug: Add missing locale dependencies of fortify tests + + The missing dependencies result in failures like this if make check + is invoked with sufficient parallelism for the debug subdirectory: + + FAIL: debug/tst-chk2 + FAIL: debug/tst-chk3 + FAIL: debug/tst-chk4 + FAIL: debug/tst-chk5 + FAIL: debug/tst-chk6 + FAIL: debug/tst-lfschk1 + FAIL: debug/tst-lfschk2 + FAIL: debug/tst-lfschk3 + FAIL: debug/tst-lfschk4 + FAIL: debug/tst-lfschk5 + FAIL: debug/tst-lfschk6 + +diff --git a/debug/Makefile b/debug/Makefile +index 506cebc3c4ca19ff..5e45c9b41077f2fd 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -188,6 +188,17 @@ LOCALES := de_DE.UTF-8 + include ../gen-locales.mk + + $(objpfx)tst-chk1.out: $(gen-locales) ++$(objpfx)tst-chk2.out: $(gen-locales) ++$(objpfx)tst-chk3.out: $(gen-locales) ++$(objpfx)tst-chk4.out: $(gen-locales) ++$(objpfx)tst-chk5.out: $(gen-locales) ++$(objpfx)tst-chk6.out: $(gen-locales) ++$(objpfx)tst-lfschk1.out: $(gen-locales) ++$(objpfx)tst-lfschk2.out: $(gen-locales) ++$(objpfx)tst-lfschk3.out: $(gen-locales) ++$(objpfx)tst-lfschk4.out: $(gen-locales) ++$(objpfx)tst-lfschk5.out: $(gen-locales) ++$(objpfx)tst-lfschk6.out: $(gen-locales) + endif + + sLIBdir := $(shell echo $(slibdir) | sed 's,lib\(\|64\)$$,\\\\$$LIB,') diff --git a/SOURCES/glibc-rh2033684-8.patch b/SOURCES/glibc-rh2033684-8.patch new file mode 100644 index 0000000..5b90b20 --- /dev/null +++ b/SOURCES/glibc-rh2033684-8.patch @@ -0,0 +1,357 @@ +commit ad6f2a010c2ce759936de4747f6e0d53991912f8 +Author: Siddhesh Poyarekar +Date: Wed Oct 20 18:13:05 2021 +0530 + + debug: Add tests for _FORTIFY_SOURCE=3 + + Add some testing coverage for _FORTIFY_SOURCE=3. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Adhemerval Zanella + +diff --git a/debug/Makefile b/debug/Makefile +index 5e45c9b41077f2fd..81361438fc3d2aa9 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -120,6 +120,8 @@ CFLAGS-tst-chk3.c += -Wno-format -Wno-deprecated-declarations -Wno-error + CFLAGS-tst-chk4.cc += -Wno-format -Wno-deprecated-declarations -Wno-error + CFLAGS-tst-chk5.cc += -Wno-format -Wno-deprecated-declarations -Wno-error + CFLAGS-tst-chk6.cc += -Wno-format -Wno-deprecated-declarations -Wno-error ++CFLAGS-tst-chk7.c += -Wno-format -Wno-deprecated-declarations -Wno-error ++CFLAGS-tst-chk8.cc += -Wno-format -Wno-deprecated-declarations -Wno-error + CFLAGS-tst-lfschk1.c += -Wno-format -Wno-deprecated-declarations -Wno-error + CFLAGS-tst-lfschk2.c += -Wno-format -Wno-deprecated-declarations -Wno-error + CFLAGS-tst-lfschk3.c += -Wno-format -Wno-deprecated-declarations -Wno-error +@@ -129,6 +131,7 @@ CFLAGS-tst-lfschk6.cc += -Wno-format -Wno-deprecated-declarations -Wno-error + LDLIBS-tst-chk4 = -lstdc++ + LDLIBS-tst-chk5 = -lstdc++ + LDLIBS-tst-chk6 = -lstdc++ ++LDLIBS-tst-chk8 = -lstdc++ + LDLIBS-tst-lfschk4 = -lstdc++ + LDLIBS-tst-lfschk5 = -lstdc++ + LDLIBS-tst-lfschk6 = -lstdc++ +@@ -150,16 +153,16 @@ CFLAGS-tst-ssp-1.c += -fstack-protector-all + + tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \ + tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \ +- tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \ +- tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 tst-backtrace4 \ +- tst-backtrace5 tst-backtrace6 ++ tst-chk4 tst-chk5 tst-chk6 tst-chk7 tst-chk8 tst-lfschk4 tst-lfschk5 \ ++ tst-lfschk6 tst-longjmp_chk2 tst-backtrace2 tst-backtrace3 \ ++ tst-backtrace4 tst-backtrace5 tst-backtrace6 + + ifeq ($(have-ssp),yes) + tests += tst-ssp-1 + endif + + ifeq (,$(CXX)) +-tests-unsupported = tst-chk4 tst-chk5 tst-chk6 \ ++tests-unsupported = tst-chk4 tst-chk5 tst-chk6 tst-chk8 \ + tst-lfschk4 tst-lfschk5 tst-lfschk6 + endif + +@@ -193,6 +196,8 @@ $(objpfx)tst-chk3.out: $(gen-locales) + $(objpfx)tst-chk4.out: $(gen-locales) + $(objpfx)tst-chk5.out: $(gen-locales) + $(objpfx)tst-chk6.out: $(gen-locales) ++$(objpfx)tst-chk7.out: $(gen-locales) ++$(objpfx)tst-chk8.out: $(gen-locales) + $(objpfx)tst-lfschk1.out: $(gen-locales) + $(objpfx)tst-lfschk2.out: $(gen-locales) + $(objpfx)tst-lfschk3.out: $(gen-locales) +diff --git a/debug/tst-chk1.c b/debug/tst-chk1.c +index ca2b524b2fa6404c..5e76081255316a93 100644 +--- a/debug/tst-chk1.c ++++ b/debug/tst-chk1.c +@@ -83,8 +83,14 @@ handler (int sig) + _exit (127); + } + ++#if __USE_FORTIFY_LEVEL == 3 ++volatile size_t buf_size = 10; ++#else + char buf[10]; + wchar_t wbuf[10]; ++#define buf_size sizeof (buf) ++#endif ++ + volatile size_t l0; + volatile char *p; + volatile wchar_t *wp; +@@ -123,6 +129,10 @@ int num2 = 987654; + static int + do_test (void) + { ++#if __USE_FORTIFY_LEVEL == 3 ++ char *buf = (char *) malloc (buf_size); ++ wchar_t *wbuf = (wchar_t *) malloc (buf_size * sizeof (wchar_t)); ++#endif + set_fortify_handler (handler); + + struct A { char buf1[9]; char buf2[1]; } a; +@@ -947,93 +957,93 @@ do_test (void) + + rewind (stdin); + +- if (fgets (buf, sizeof (buf), stdin) != buf ++ if (fgets (buf, buf_size, stdin) != buf + || memcmp (buf, "abcdefgh\n", 10)) + FAIL (); +- if (fgets (buf, sizeof (buf), stdin) != buf || memcmp (buf, "ABCDEFGHI", 10)) ++ if (fgets (buf, buf_size, stdin) != buf || memcmp (buf, "ABCDEFGHI", 10)) + FAIL (); + + rewind (stdin); + +- if (fgets (buf, l0 + sizeof (buf), stdin) != buf ++ if (fgets (buf, l0 + buf_size, stdin) != buf + || memcmp (buf, "abcdefgh\n", 10)) + FAIL (); + + #if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START +- if (fgets (buf, sizeof (buf) + 1, stdin) != buf) ++ if (fgets (buf, buf_size + 1, stdin) != buf) + FAIL (); + CHK_FAIL_END + + CHK_FAIL_START +- if (fgets (buf, l0 + sizeof (buf) + 1, stdin) != buf) ++ if (fgets (buf, l0 + buf_size + 1, stdin) != buf) + FAIL (); + CHK_FAIL_END + #endif + + rewind (stdin); + +- if (fgets_unlocked (buf, sizeof (buf), stdin) != buf ++ if (fgets_unlocked (buf, buf_size, stdin) != buf + || memcmp (buf, "abcdefgh\n", 10)) + FAIL (); +- if (fgets_unlocked (buf, sizeof (buf), stdin) != buf ++ if (fgets_unlocked (buf, buf_size, stdin) != buf + || memcmp (buf, "ABCDEFGHI", 10)) + FAIL (); + + rewind (stdin); + +- if (fgets_unlocked (buf, l0 + sizeof (buf), stdin) != buf ++ if (fgets_unlocked (buf, l0 + buf_size, stdin) != buf + || memcmp (buf, "abcdefgh\n", 10)) + FAIL (); + + #if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START +- if (fgets_unlocked (buf, sizeof (buf) + 1, stdin) != buf) ++ if (fgets_unlocked (buf, buf_size + 1, stdin) != buf) + FAIL (); + CHK_FAIL_END + + CHK_FAIL_START +- if (fgets_unlocked (buf, l0 + sizeof (buf) + 1, stdin) != buf) ++ if (fgets_unlocked (buf, l0 + buf_size + 1, stdin) != buf) + FAIL (); + CHK_FAIL_END + #endif + + rewind (stdin); + +- if (fread (buf, 1, sizeof (buf), stdin) != sizeof (buf) ++ if (fread (buf, 1, buf_size, stdin) != buf_size + || memcmp (buf, "abcdefgh\nA", 10)) + FAIL (); +- if (fread (buf, sizeof (buf), 1, stdin) != 1 ++ if (fread (buf, buf_size, 1, stdin) != 1 + || memcmp (buf, "BCDEFGHI\na", 10)) + FAIL (); + + rewind (stdin); + +- if (fread (buf, l0 + 1, sizeof (buf), stdin) != sizeof (buf) ++ if (fread (buf, l0 + 1, buf_size, stdin) != buf_size + || memcmp (buf, "abcdefgh\nA", 10)) + FAIL (); +- if (fread (buf, sizeof (buf), l0 + 1, stdin) != 1 ++ if (fread (buf, buf_size, l0 + 1, stdin) != 1 + || memcmp (buf, "BCDEFGHI\na", 10)) + FAIL (); + + #if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START +- if (fread (buf, 1, sizeof (buf) + 1, stdin) != sizeof (buf) + 1) ++ if (fread (buf, 1, buf_size + 1, stdin) != buf_size + 1) + FAIL (); + CHK_FAIL_END + + CHK_FAIL_START +- if (fread (buf, sizeof (buf) + 1, l0 + 1, stdin) != 1) ++ if (fread (buf, buf_size + 1, l0 + 1, stdin) != 1) + FAIL (); + CHK_FAIL_END + #endif + + rewind (stdin); + +- if (fread_unlocked (buf, 1, sizeof (buf), stdin) != sizeof (buf) ++ if (fread_unlocked (buf, 1, buf_size, stdin) != buf_size + || memcmp (buf, "abcdefgh\nA", 10)) + FAIL (); +- if (fread_unlocked (buf, sizeof (buf), 1, stdin) != 1 ++ if (fread_unlocked (buf, buf_size, 1, stdin) != 1 + || memcmp (buf, "BCDEFGHI\na", 10)) + FAIL (); + +@@ -1048,100 +1058,100 @@ do_test (void) + + rewind (stdin); + +- if (fread_unlocked (buf, l0 + 1, sizeof (buf), stdin) != sizeof (buf) ++ if (fread_unlocked (buf, l0 + 1, buf_size, stdin) != buf_size + || memcmp (buf, "abcdefgh\nA", 10)) + FAIL (); +- if (fread_unlocked (buf, sizeof (buf), l0 + 1, stdin) != 1 ++ if (fread_unlocked (buf, buf_size, l0 + 1, stdin) != 1 + || memcmp (buf, "BCDEFGHI\na", 10)) + FAIL (); + + #if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START +- if (fread_unlocked (buf, 1, sizeof (buf) + 1, stdin) != sizeof (buf) + 1) ++ if (fread_unlocked (buf, 1, buf_size + 1, stdin) != buf_size + 1) + FAIL (); + CHK_FAIL_END + + CHK_FAIL_START +- if (fread_unlocked (buf, sizeof (buf) + 1, l0 + 1, stdin) != 1) ++ if (fread_unlocked (buf, buf_size + 1, l0 + 1, stdin) != 1) + FAIL (); + CHK_FAIL_END + #endif + + lseek (fileno (stdin), 0, SEEK_SET); + +- if (read (fileno (stdin), buf, sizeof (buf) - 1) != sizeof (buf) - 1 ++ if (read (fileno (stdin), buf, buf_size - 1) != buf_size - 1 + || memcmp (buf, "abcdefgh\n", 9)) + FAIL (); +- if (read (fileno (stdin), buf, sizeof (buf) - 1) != sizeof (buf) - 1 ++ if (read (fileno (stdin), buf, buf_size - 1) != buf_size - 1 + || memcmp (buf, "ABCDEFGHI", 9)) + FAIL (); + + lseek (fileno (stdin), 0, SEEK_SET); + +- if (read (fileno (stdin), buf, l0 + sizeof (buf) - 1) != sizeof (buf) - 1 ++ if (read (fileno (stdin), buf, l0 + buf_size - 1) != buf_size - 1 + || memcmp (buf, "abcdefgh\n", 9)) + FAIL (); + + #if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START +- if (read (fileno (stdin), buf, sizeof (buf) + 1) != sizeof (buf) + 1) ++ if (read (fileno (stdin), buf, buf_size + 1) != buf_size + 1) + FAIL (); + CHK_FAIL_END + + CHK_FAIL_START +- if (read (fileno (stdin), buf, l0 + sizeof (buf) + 1) != sizeof (buf) + 1) ++ if (read (fileno (stdin), buf, l0 + buf_size + 1) != buf_size + 1) + FAIL (); + CHK_FAIL_END + #endif + +- if (pread (fileno (stdin), buf, sizeof (buf) - 1, sizeof (buf) - 2) +- != sizeof (buf) - 1 ++ if (pread (fileno (stdin), buf, buf_size - 1, buf_size - 2) ++ != buf_size - 1 + || memcmp (buf, "\nABCDEFGH", 9)) + FAIL (); +- if (pread (fileno (stdin), buf, sizeof (buf) - 1, 0) != sizeof (buf) - 1 ++ if (pread (fileno (stdin), buf, buf_size - 1, 0) != buf_size - 1 + || memcmp (buf, "abcdefgh\n", 9)) + FAIL (); +- if (pread (fileno (stdin), buf, l0 + sizeof (buf) - 1, sizeof (buf) - 3) +- != sizeof (buf) - 1 ++ if (pread (fileno (stdin), buf, l0 + buf_size - 1, buf_size - 3) ++ != buf_size - 1 + || memcmp (buf, "h\nABCDEFG", 9)) + FAIL (); + + #if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START +- if (pread (fileno (stdin), buf, sizeof (buf) + 1, 2 * sizeof (buf)) +- != sizeof (buf) + 1) ++ if (pread (fileno (stdin), buf, buf_size + 1, 2 * buf_size) ++ != buf_size + 1) + FAIL (); + CHK_FAIL_END + + CHK_FAIL_START +- if (pread (fileno (stdin), buf, l0 + sizeof (buf) + 1, 2 * sizeof (buf)) +- != sizeof (buf) + 1) ++ if (pread (fileno (stdin), buf, l0 + buf_size + 1, 2 * buf_size) ++ != buf_size + 1) + FAIL (); + CHK_FAIL_END + #endif + +- if (pread64 (fileno (stdin), buf, sizeof (buf) - 1, sizeof (buf) - 2) +- != sizeof (buf) - 1 ++ if (pread64 (fileno (stdin), buf, buf_size - 1, buf_size - 2) ++ != buf_size - 1 + || memcmp (buf, "\nABCDEFGH", 9)) + FAIL (); +- if (pread64 (fileno (stdin), buf, sizeof (buf) - 1, 0) != sizeof (buf) - 1 ++ if (pread64 (fileno (stdin), buf, buf_size - 1, 0) != buf_size - 1 + || memcmp (buf, "abcdefgh\n", 9)) + FAIL (); +- if (pread64 (fileno (stdin), buf, l0 + sizeof (buf) - 1, sizeof (buf) - 3) +- != sizeof (buf) - 1 ++ if (pread64 (fileno (stdin), buf, l0 + buf_size - 1, buf_size - 3) ++ != buf_size - 1 + || memcmp (buf, "h\nABCDEFG", 9)) + FAIL (); + + #if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START +- if (pread64 (fileno (stdin), buf, sizeof (buf) + 1, 2 * sizeof (buf)) +- != sizeof (buf) + 1) ++ if (pread64 (fileno (stdin), buf, buf_size + 1, 2 * buf_size) ++ != buf_size + 1) + FAIL (); + CHK_FAIL_END + + CHK_FAIL_START +- if (pread64 (fileno (stdin), buf, l0 + sizeof (buf) + 1, 2 * sizeof (buf)) +- != sizeof (buf) + 1) ++ if (pread64 (fileno (stdin), buf, l0 + buf_size + 1, 2 * buf_size) ++ != buf_size + 1) + FAIL (); + CHK_FAIL_END + #endif +@@ -1179,7 +1189,7 @@ do_test (void) + CHK_FAIL2_END + + CHK_FAIL2_START +- snprintf (buf, sizeof (buf), "%3$d\n", 1, 2, 3, 4); ++ snprintf (buf, buf_size, "%3$d\n", 1, 2, 3, 4); + CHK_FAIL2_END + + int sp[2]; +diff --git a/debug/tst-chk7.c b/debug/tst-chk7.c +new file mode 100644 +index 0000000000000000..2a7b32381268135c +--- /dev/null ++++ b/debug/tst-chk7.c +@@ -0,0 +1,2 @@ ++#define _FORTIFY_SOURCE 3 ++#include "tst-chk1.c" +diff --git a/debug/tst-chk8.cc b/debug/tst-chk8.cc +new file mode 100644 +index 0000000000000000..2a7b32381268135c +--- /dev/null ++++ b/debug/tst-chk8.cc +@@ -0,0 +1,2 @@ ++#define _FORTIFY_SOURCE 3 ++#include "tst-chk1.c" diff --git a/SOURCES/glibc-rh2033684-9.patch b/SOURCES/glibc-rh2033684-9.patch new file mode 100644 index 0000000..467ece4 --- /dev/null +++ b/SOURCES/glibc-rh2033684-9.patch @@ -0,0 +1,23 @@ +commit ae23fa3e5fe24daf94fc7f8e5268bb8ceeda7477 +Author: Siddhesh Poyarekar +Date: Thu Dec 16 07:19:14 2021 +0530 + + __glibc_unsafe_len: Fix comment + + We know that the length is *unsafe*. + + Signed-off-by: Siddhesh Poyarekar + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 17b84a2e6c69d961..147339957c4ad490 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -150,7 +150,7 @@ + __s, __osz)) \ + && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz)) + +-/* Conversely, we know at compile time that the length is safe if the ++/* Conversely, we know at compile time that the length is unsafe if the + __L * __S <= __OBJSZ condition can be folded to a constant and if it is + false. */ + #define __glibc_unsafe_len(__l, __s, __osz) \ diff --git a/SOURCES/glibc-rh2037416-1.patch b/SOURCES/glibc-rh2037416-1.patch new file mode 100644 index 0000000..3fddefe --- /dev/null +++ b/SOURCES/glibc-rh2037416-1.patch @@ -0,0 +1,136 @@ +From 07b427296b8d59f439144029d9a948f6c1ce0a31 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:30:27 +0100 +Subject: [PATCH] [1/5] AArch64: Improve A64FX memset for small sizes + +Improve performance of small memsets by reducing instruction counts and +improving code alignment. Bench-memset shows 35-45% performance gain for +small sizes. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 96 +++++++++--------------- + 1 file changed, 36 insertions(+), 60 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index ce54e5418b..cf3d402ef6 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -51,78 +51,54 @@ + .endm + + .macro st1b_unroll first=0, last=7 +- st1b z0.b, p0, [dst, #\first, mul vl] ++ st1b z0.b, p0, [dst, \first, mul vl] + .if \last-\first + st1b_unroll "(\first+1)", \last + .endif + .endm + +- .macro shortcut_for_small_size exit +- // if rest <= vector_length * 2 +- whilelo p0.b, xzr, count +- whilelo p1.b, vector_length, count +- b.last 1f +- st1b z0.b, p0, [dstin, #0, mul vl] +- st1b z0.b, p1, [dstin, #1, mul vl] +- ret +-1: // if rest > vector_length * 8 +- cmp count, vector_length, lsl 3 // vector_length * 8 +- b.hi \exit +- // if rest <= vector_length * 4 +- lsl tmp1, vector_length, 1 // vector_length * 2 +- whilelo p2.b, tmp1, count +- incb tmp1 +- whilelo p3.b, tmp1, count +- b.last 1f +- st1b z0.b, p0, [dstin, #0, mul vl] +- st1b z0.b, p1, [dstin, #1, mul vl] +- st1b z0.b, p2, [dstin, #2, mul vl] +- st1b z0.b, p3, [dstin, #3, mul vl] +- ret +-1: // if rest <= vector_length * 8 +- lsl tmp1, vector_length, 2 // vector_length * 4 +- whilelo p4.b, tmp1, count +- incb tmp1 +- whilelo p5.b, tmp1, count +- b.last 1f +- st1b z0.b, p0, [dstin, #0, mul vl] +- st1b z0.b, p1, [dstin, #1, mul vl] +- st1b z0.b, p2, [dstin, #2, mul vl] +- st1b z0.b, p3, [dstin, #3, mul vl] +- st1b z0.b, p4, [dstin, #4, mul vl] +- st1b z0.b, p5, [dstin, #5, mul vl] +- ret +-1: lsl tmp1, vector_length, 2 // vector_length * 4 +- incb tmp1 // vector_length * 5 +- incb tmp1 // vector_length * 6 +- whilelo p6.b, tmp1, count +- incb tmp1 +- whilelo p7.b, tmp1, count +- st1b z0.b, p0, [dstin, #0, mul vl] +- st1b z0.b, p1, [dstin, #1, mul vl] +- st1b z0.b, p2, [dstin, #2, mul vl] +- st1b z0.b, p3, [dstin, #3, mul vl] +- st1b z0.b, p4, [dstin, #4, mul vl] +- st1b z0.b, p5, [dstin, #5, mul vl] +- st1b z0.b, p6, [dstin, #6, mul vl] +- st1b z0.b, p7, [dstin, #7, mul vl] +- ret +- .endm + +-ENTRY (MEMSET) ++#undef BTI_C ++#define BTI_C + ++ENTRY (MEMSET) + PTR_ARG (0) + SIZE_ARG (2) + +- cbnz count, 1f +- ret +-1: dup z0.b, valw + cntb vector_length +- // shortcut for less than vector_length * 8 +- // gives a free ptrue to p0.b for n >= vector_length +- shortcut_for_small_size L(vl_agnostic) +- // end of shortcut ++ dup z0.b, valw ++ whilelo p0.b, vector_length, count ++ b.last 1f ++ whilelo p1.b, xzr, count ++ st1b z0.b, p1, [dstin, 0, mul vl] ++ st1b z0.b, p0, [dstin, 1, mul vl] ++ ret ++ ++ // count >= vector_length * 2 ++1: cmp count, vector_length, lsl 2 ++ add dstend, dstin, count ++ b.hi 1f ++ st1b z0.b, p0, [dstin, 0, mul vl] ++ st1b z0.b, p0, [dstin, 1, mul vl] ++ st1b z0.b, p0, [dstend, -2, mul vl] ++ st1b z0.b, p0, [dstend, -1, mul vl] ++ ret ++ ++ // count > vector_length * 4 ++1: lsl tmp1, vector_length, 3 ++ cmp count, tmp1 ++ b.hi L(vl_agnostic) ++ st1b z0.b, p0, [dstin, 0, mul vl] ++ st1b z0.b, p0, [dstin, 1, mul vl] ++ st1b z0.b, p0, [dstin, 2, mul vl] ++ st1b z0.b, p0, [dstin, 3, mul vl] ++ st1b z0.b, p0, [dstend, -4, mul vl] ++ st1b z0.b, p0, [dstend, -3, mul vl] ++ st1b z0.b, p0, [dstend, -2, mul vl] ++ st1b z0.b, p0, [dstend, -1, mul vl] ++ ret + ++ .p2align 4 + L(vl_agnostic): // VL Agnostic + mov rest, count + mov dst, dstin +-- +2.31.1 + diff --git a/SOURCES/glibc-rh2037416-2.patch b/SOURCES/glibc-rh2037416-2.patch new file mode 100644 index 0000000..e991e91 --- /dev/null +++ b/SOURCES/glibc-rh2037416-2.patch @@ -0,0 +1,131 @@ +From 9bc2ed8f46d80859a5596789cc9e8cc2de84b0e7 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:39:37 +0100 +Subject: [PATCH] [2/5] AArch64: Improve A64FX memset for large sizes + +Improve performance of large memsets. Simplify alignment code. For zero memset +use DC ZVA, which almost doubles performance. For non-zero memsets use the +unroll8 loop which is about 10% faster. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 85 +++++++----------------- + 1 file changed, 25 insertions(+), 60 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index cf3d402ef6..75cf43ae79 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -27,14 +27,11 @@ + */ + + #define L1_SIZE (64*1024) // L1 64KB +-#define L2_SIZE (8*1024*1024) // L2 8MB - 1MB ++#define L2_SIZE (8*1024*1024) // L2 8MB + #define CACHE_LINE_SIZE 256 + #define PF_DIST_L1 (CACHE_LINE_SIZE * 16) // Prefetch distance L1 +-#define ZF_DIST (CACHE_LINE_SIZE * 21) // Zerofill distance +-#define rest x8 ++#define rest x2 + #define vector_length x9 +-#define vl_remainder x10 // vector_length remainder +-#define cl_remainder x11 // CACHE_LINE_SIZE remainder + + #if HAVE_AARCH64_SVE_ASM + # if IS_IN (libc) +@@ -42,14 +39,6 @@ + + .arch armv8.2-a+sve + +- .macro dc_zva times +- dc zva, tmp1 +- add tmp1, tmp1, CACHE_LINE_SIZE +- .if \times-1 +- dc_zva "(\times-1)" +- .endif +- .endm +- + .macro st1b_unroll first=0, last=7 + st1b z0.b, p0, [dst, \first, mul vl] + .if \last-\first +@@ -188,54 +177,30 @@ L(L1_prefetch): // if rest >= L1_SIZE + cbnz rest, L(unroll32) + ret + +-L(L2): +- // align dst address at vector_length byte boundary +- sub tmp1, vector_length, 1 +- ands tmp2, dst, tmp1 +- // if vl_remainder == 0 +- b.eq 1f +- sub vl_remainder, vector_length, tmp2 +- // process remainder until the first vector_length boundary +- whilelt p2.b, xzr, vl_remainder +- st1b z0.b, p2, [dst] +- add dst, dst, vl_remainder +- sub rest, rest, vl_remainder +- // align dstin address at CACHE_LINE_SIZE byte boundary +-1: mov tmp1, CACHE_LINE_SIZE +- ands tmp2, dst, CACHE_LINE_SIZE - 1 +- // if cl_remainder == 0 +- b.eq L(L2_dc_zva) +- sub cl_remainder, tmp1, tmp2 +- // process remainder until the first CACHE_LINE_SIZE boundary +- mov tmp1, xzr // index +-2: whilelt p2.b, tmp1, cl_remainder +- st1b z0.b, p2, [dst, tmp1] +- incb tmp1 +- cmp tmp1, cl_remainder +- b.lo 2b +- add dst, dst, cl_remainder +- sub rest, rest, cl_remainder +- +-L(L2_dc_zva): +- // zero fill +- mov tmp1, dst +- dc_zva (ZF_DIST / CACHE_LINE_SIZE) - 1 +- mov zva_len, ZF_DIST +- add tmp1, zva_len, CACHE_LINE_SIZE * 2 +- // unroll ++ // count >= L2_SIZE + .p2align 3 +-1: st1b_unroll 0, 3 +- add tmp2, dst, zva_len +- dc zva, tmp2 +- st1b_unroll 4, 7 +- add tmp2, tmp2, CACHE_LINE_SIZE +- dc zva, tmp2 +- add dst, dst, CACHE_LINE_SIZE * 2 +- sub rest, rest, CACHE_LINE_SIZE * 2 +- cmp rest, tmp1 // ZF_DIST + CACHE_LINE_SIZE * 2 +- b.ge 1b +- cbnz rest, L(unroll8) +- ret ++L(L2): ++ tst valw, 255 ++ b.ne L(unroll8) ++ // align dst to CACHE_LINE_SIZE byte boundary ++ and tmp2, dst, CACHE_LINE_SIZE - 1 ++ st1b z0.b, p0, [dst, 0, mul vl] ++ st1b z0.b, p0, [dst, 1, mul vl] ++ st1b z0.b, p0, [dst, 2, mul vl] ++ st1b z0.b, p0, [dst, 3, mul vl] ++ sub dst, dst, tmp2 ++ add count, count, tmp2 ++ ++ // clear cachelines using DC ZVA ++ sub count, count, CACHE_LINE_SIZE * 2 ++ .p2align 4 ++1: add dst, dst, CACHE_LINE_SIZE ++ dc zva, dst ++ subs count, count, CACHE_LINE_SIZE ++ b.hi 1b ++ add count, count, CACHE_LINE_SIZE ++ add dst, dst, CACHE_LINE_SIZE ++ b L(last) + + END (MEMSET) + libc_hidden_builtin_def (MEMSET) +-- +2.31.1 + diff --git a/SOURCES/glibc-rh2037416-3.patch b/SOURCES/glibc-rh2037416-3.patch new file mode 100644 index 0000000..3ac7aa2 --- /dev/null +++ b/SOURCES/glibc-rh2037416-3.patch @@ -0,0 +1,80 @@ +From 186092c6ba8825598ffdbf15dbf0823c771f560d Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:42:07 +0100 +Subject: [PATCH] [3/5] AArch64: Improve A64FX memset for remaining bytes + +Simplify handling of remaining bytes. Avoid lots of taken branches and complex +whilelo computations, instead unconditionally write vectors from the end. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 46 +++++++----------------- + 1 file changed, 13 insertions(+), 33 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index 75cf43ae79..337c86be6f 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -130,38 +130,19 @@ L(unroll8): + b 1b + + L(last): +- whilelo p0.b, xzr, rest +- whilelo p1.b, vector_length, rest +- b.last 1f +- st1b z0.b, p0, [dst, #0, mul vl] +- st1b z0.b, p1, [dst, #1, mul vl] +- ret +-1: lsl tmp1, vector_length, 1 // vector_length * 2 +- whilelo p2.b, tmp1, rest +- incb tmp1 +- whilelo p3.b, tmp1, rest +- b.last 1f +- st1b z0.b, p0, [dst, #0, mul vl] +- st1b z0.b, p1, [dst, #1, mul vl] +- st1b z0.b, p2, [dst, #2, mul vl] +- st1b z0.b, p3, [dst, #3, mul vl] +- ret +-1: lsl tmp1, vector_length, 2 // vector_length * 4 +- whilelo p4.b, tmp1, rest +- incb tmp1 +- whilelo p5.b, tmp1, rest +- incb tmp1 +- whilelo p6.b, tmp1, rest +- incb tmp1 +- whilelo p7.b, tmp1, rest +- st1b z0.b, p0, [dst, #0, mul vl] +- st1b z0.b, p1, [dst, #1, mul vl] +- st1b z0.b, p2, [dst, #2, mul vl] +- st1b z0.b, p3, [dst, #3, mul vl] +- st1b z0.b, p4, [dst, #4, mul vl] +- st1b z0.b, p5, [dst, #5, mul vl] +- st1b z0.b, p6, [dst, #6, mul vl] +- st1b z0.b, p7, [dst, #7, mul vl] ++ cmp count, vector_length, lsl 1 ++ b.ls 2f ++ add tmp2, vector_length, vector_length, lsl 2 ++ cmp count, tmp2 ++ b.ls 5f ++ st1b z0.b, p0, [dstend, -8, mul vl] ++ st1b z0.b, p0, [dstend, -7, mul vl] ++ st1b z0.b, p0, [dstend, -6, mul vl] ++5: st1b z0.b, p0, [dstend, -5, mul vl] ++ st1b z0.b, p0, [dstend, -4, mul vl] ++ st1b z0.b, p0, [dstend, -3, mul vl] ++2: st1b z0.b, p0, [dstend, -2, mul vl] ++ st1b z0.b, p0, [dstend, -1, mul vl] + ret + + L(L1_prefetch): // if rest >= L1_SIZE +@@ -199,7 +180,6 @@ L(L2): + subs count, count, CACHE_LINE_SIZE + b.hi 1b + add count, count, CACHE_LINE_SIZE +- add dst, dst, CACHE_LINE_SIZE + b L(last) + + END (MEMSET) +-- +2.31.1 + diff --git a/SOURCES/glibc-rh2037416-4.patch b/SOURCES/glibc-rh2037416-4.patch new file mode 100644 index 0000000..e057eeb --- /dev/null +++ b/SOURCES/glibc-rh2037416-4.patch @@ -0,0 +1,51 @@ +From e69d9981f858a38e19304e6ff5ebdf89f2cb0ba0 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:44:27 +0100 +Subject: [PATCH] [4/5] AArch64: Improve A64FX memset by removing unroll32 + +Remove unroll32 code since it doesn't improve performance. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 18 +----------------- + 1 file changed, 1 insertion(+), 17 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index 337c86be6f..ef0315658a 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -102,22 +102,6 @@ L(vl_agnostic): // VL Agnostic + ccmp vector_length, tmp1, 0, cs + b.eq L(L1_prefetch) + +-L(unroll32): +- lsl tmp1, vector_length, 3 // vector_length * 8 +- lsl tmp2, vector_length, 5 // vector_length * 32 +- .p2align 3 +-1: cmp rest, tmp2 +- b.cc L(unroll8) +- st1b_unroll +- add dst, dst, tmp1 +- st1b_unroll +- add dst, dst, tmp1 +- st1b_unroll +- add dst, dst, tmp1 +- st1b_unroll +- add dst, dst, tmp1 +- sub rest, rest, tmp2 +- b 1b + + L(unroll8): + lsl tmp1, vector_length, 3 +@@ -155,7 +139,7 @@ L(L1_prefetch): // if rest >= L1_SIZE + sub rest, rest, CACHE_LINE_SIZE * 2 + cmp rest, L1_SIZE + b.ge 1b +- cbnz rest, L(unroll32) ++ cbnz rest, L(unroll8) + ret + + // count >= L2_SIZE +-- +2.31.1 + diff --git a/SOURCES/glibc-rh2037416-5.patch b/SOURCES/glibc-rh2037416-5.patch new file mode 100644 index 0000000..c92c2cf --- /dev/null +++ b/SOURCES/glibc-rh2037416-5.patch @@ -0,0 +1,96 @@ +From a5db6a5cae6a92d1675c013e5c8d972768721576 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Tue, 10 Aug 2021 13:46:20 +0100 +Subject: [PATCH] [5/5] AArch64: Improve A64FX memset medium loops + +Simplify the code for memsets smaller than L1. Improve the unroll8 and +L1_prefetch loops. + +Reviewed-by: Naohiro Tamura +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 45 ++++++++++-------------- + 1 file changed, 19 insertions(+), 26 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index ef0315658a..7bf759b6a7 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -30,7 +30,6 @@ + #define L2_SIZE (8*1024*1024) // L2 8MB + #define CACHE_LINE_SIZE 256 + #define PF_DIST_L1 (CACHE_LINE_SIZE * 16) // Prefetch distance L1 +-#define rest x2 + #define vector_length x9 + + #if HAVE_AARCH64_SVE_ASM +@@ -89,29 +88,19 @@ ENTRY (MEMSET) + + .p2align 4 + L(vl_agnostic): // VL Agnostic +- mov rest, count + mov dst, dstin +- add dstend, dstin, count +- // if rest >= L2_SIZE && vector_length == 64 then L(L2) +- mov tmp1, 64 +- cmp rest, L2_SIZE +- ccmp vector_length, tmp1, 0, cs +- b.eq L(L2) +- // if rest >= L1_SIZE && vector_length == 64 then L(L1_prefetch) +- cmp rest, L1_SIZE +- ccmp vector_length, tmp1, 0, cs +- b.eq L(L1_prefetch) +- ++ cmp count, L1_SIZE ++ b.hi L(L1_prefetch) + ++ // count >= 8 * vector_length + L(unroll8): +- lsl tmp1, vector_length, 3 +- .p2align 3 +-1: cmp rest, tmp1 +- b.cc L(last) +- st1b_unroll ++ sub count, count, tmp1 ++ .p2align 4 ++1: st1b_unroll 0, 7 + add dst, dst, tmp1 +- sub rest, rest, tmp1 +- b 1b ++ subs count, count, tmp1 ++ b.hi 1b ++ add count, count, tmp1 + + L(last): + cmp count, vector_length, lsl 1 +@@ -129,18 +118,22 @@ L(last): + st1b z0.b, p0, [dstend, -1, mul vl] + ret + +-L(L1_prefetch): // if rest >= L1_SIZE ++ // count >= L1_SIZE + .p2align 3 ++L(L1_prefetch): ++ cmp count, L2_SIZE ++ b.hs L(L2) ++ cmp vector_length, 64 ++ b.ne L(unroll8) + 1: st1b_unroll 0, 3 + prfm pstl1keep, [dst, PF_DIST_L1] + st1b_unroll 4, 7 + prfm pstl1keep, [dst, PF_DIST_L1 + CACHE_LINE_SIZE] + add dst, dst, CACHE_LINE_SIZE * 2 +- sub rest, rest, CACHE_LINE_SIZE * 2 +- cmp rest, L1_SIZE +- b.ge 1b +- cbnz rest, L(unroll8) +- ret ++ sub count, count, CACHE_LINE_SIZE * 2 ++ cmp count, PF_DIST_L1 ++ b.hs 1b ++ b L(unroll8) + + // count >= L2_SIZE + .p2align 3 +-- +2.31.1 + diff --git a/SOURCES/glibc-rh2037416-6.patch b/SOURCES/glibc-rh2037416-6.patch new file mode 100644 index 0000000..b2522ad --- /dev/null +++ b/SOURCES/glibc-rh2037416-6.patch @@ -0,0 +1,39 @@ +From 1d9f99ce1b3788d1897cb53a76d57e973111b8fe Mon Sep 17 00:00:00 2001 +From: Naohiro Tamura +Date: Fri, 27 Aug 2021 05:03:04 +0000 +Subject: [PATCH] AArch64: Update A64FX memset not to degrade at 16KB + +This patch updates unroll8 code so as not to degrade at the peak +performance 16KB for both FX1000 and FX700. + +Inserted 2 instructions at the beginning of the unroll8 loop, +cmp and branch, are a workaround that is found heuristically. + +Reviewed-by: Wilco Dijkstra +--- + sysdeps/aarch64/multiarch/memset_a64fx.S | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S +index 7bf759b6a7..f7dfdaace7 100644 +--- a/sysdeps/aarch64/multiarch/memset_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memset_a64fx.S +@@ -96,7 +96,14 @@ L(vl_agnostic): // VL Agnostic + L(unroll8): + sub count, count, tmp1 + .p2align 4 +-1: st1b_unroll 0, 7 ++ // The 2 instructions at the beginning of the following loop, ++ // cmp and branch, are a workaround so as not to degrade at ++ // the peak performance 16KB. ++ // It is found heuristically and the branch condition, b.ne, ++ // is chosen intentionally never to jump. ++1: cmp xzr, xzr ++ b.ne 1b ++ st1b_unroll 0, 7 + add dst, dst, tmp1 + subs count, count, tmp1 + b.hi 1b +-- +2.31.1 + diff --git a/SOURCES/glibc-rh2037416-7.patch b/SOURCES/glibc-rh2037416-7.patch new file mode 100644 index 0000000..e57fef7 --- /dev/null +++ b/SOURCES/glibc-rh2037416-7.patch @@ -0,0 +1,32 @@ +From 381b29616abb82babc8163bdf516c6da87544b35 Mon Sep 17 00:00:00 2001 +From: Naohiro Tamura +Date: Fri, 24 Sep 2021 07:49:59 +0000 +Subject: [PATCH] aarch64: Disable A64FX memcpy/memmove BTI unconditionally + +This patch disables A64FX memcpy/memmove BTI instruction insertion +unconditionally such as A64FX memset patch [1] for performance. + +[1] commit 07b427296b8d59f439144029d9a948f6c1ce0a31 + +Reviewed-by: Szabolcs Nagy +--- + sysdeps/aarch64/multiarch/memcpy_a64fx.S | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S +index 65528405bb..ae7464e09f 100644 +--- a/sysdeps/aarch64/multiarch/memcpy_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S +@@ -19,6 +19,9 @@ + + #include + ++#undef BTI_C ++#define BTI_C ++ + /* Assumptions: + * + * ARMv8.2-a, AArch64, unaligned accesses, sve +-- +2.31.1 + diff --git a/SOURCES/glibc-rh2037416-8.patch b/SOURCES/glibc-rh2037416-8.patch new file mode 100644 index 0000000..6a68332 --- /dev/null +++ b/SOURCES/glibc-rh2037416-8.patch @@ -0,0 +1,630 @@ +From b31bd11454fade731e5158b1aea40b133ae19926 Mon Sep 17 00:00:00 2001 +From: Wilco Dijkstra +Date: Thu, 2 Dec 2021 18:33:26 +0000 +Subject: [PATCH] AArch64: Improve A64FX memcpy + +v2 is a complete rewrite of the A64FX memcpy. Performance is improved +by streamlining the code, aligning all large copies and using a single +unrolled loop for all sizes. The code size for memcpy and memmove goes +down from 1796 bytes to 868 bytes. Performance is better in all cases: +bench-memcpy-random is 2.3% faster overall, bench-memcpy-large is ~33% +faster for large sizes, bench-memcpy-walk is 25% faster for small sizes +and 20% for the largest sizes. The geomean of all tests in bench-memcpy +is 5.1% faster, and total time is reduced by 4%. + +Reviewed-by: Szabolcs Nagy +--- + sysdeps/aarch64/multiarch/memcpy_a64fx.S | 546 ++++++++++------------- + 1 file changed, 225 insertions(+), 321 deletions(-) + +diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S +index ae7464e09f..0b306925e6 100644 +--- a/sysdeps/aarch64/multiarch/memcpy_a64fx.S ++++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S +@@ -28,20 +28,15 @@ + * + */ + +-#define L2_SIZE (8*1024*1024)/2 // L2 8MB/2 +-#define CACHE_LINE_SIZE 256 +-#define ZF_DIST (CACHE_LINE_SIZE * 21) // Zerofill distance +-#define dest x0 +-#define src x1 +-#define n x2 // size +-#define tmp1 x3 +-#define tmp2 x4 +-#define tmp3 x5 +-#define rest x6 +-#define dest_ptr x7 +-#define src_ptr x8 +-#define vector_length x9 +-#define cl_remainder x10 // CACHE_LINE_SIZE remainder ++#define dstin x0 ++#define src x1 ++#define n x2 ++#define dst x3 ++#define dstend x4 ++#define srcend x5 ++#define tmp x6 ++#define vlen x7 ++#define vlen8 x8 + + #if HAVE_AARCH64_SVE_ASM + # if IS_IN (libc) +@@ -50,45 +45,37 @@ + + .arch armv8.2-a+sve + +- .macro dc_zva times +- dc zva, tmp1 +- add tmp1, tmp1, CACHE_LINE_SIZE +- .if \times-1 +- dc_zva "(\times-1)" +- .endif +- .endm +- + .macro ld1b_unroll8 +- ld1b z0.b, p0/z, [src_ptr, #0, mul vl] +- ld1b z1.b, p0/z, [src_ptr, #1, mul vl] +- ld1b z2.b, p0/z, [src_ptr, #2, mul vl] +- ld1b z3.b, p0/z, [src_ptr, #3, mul vl] +- ld1b z4.b, p0/z, [src_ptr, #4, mul vl] +- ld1b z5.b, p0/z, [src_ptr, #5, mul vl] +- ld1b z6.b, p0/z, [src_ptr, #6, mul vl] +- ld1b z7.b, p0/z, [src_ptr, #7, mul vl] ++ ld1b z0.b, p0/z, [src, 0, mul vl] ++ ld1b z1.b, p0/z, [src, 1, mul vl] ++ ld1b z2.b, p0/z, [src, 2, mul vl] ++ ld1b z3.b, p0/z, [src, 3, mul vl] ++ ld1b z4.b, p0/z, [src, 4, mul vl] ++ ld1b z5.b, p0/z, [src, 5, mul vl] ++ ld1b z6.b, p0/z, [src, 6, mul vl] ++ ld1b z7.b, p0/z, [src, 7, mul vl] + .endm + + .macro stld1b_unroll4a +- st1b z0.b, p0, [dest_ptr, #0, mul vl] +- st1b z1.b, p0, [dest_ptr, #1, mul vl] +- ld1b z0.b, p0/z, [src_ptr, #0, mul vl] +- ld1b z1.b, p0/z, [src_ptr, #1, mul vl] +- st1b z2.b, p0, [dest_ptr, #2, mul vl] +- st1b z3.b, p0, [dest_ptr, #3, mul vl] +- ld1b z2.b, p0/z, [src_ptr, #2, mul vl] +- ld1b z3.b, p0/z, [src_ptr, #3, mul vl] ++ st1b z0.b, p0, [dst, 0, mul vl] ++ st1b z1.b, p0, [dst, 1, mul vl] ++ ld1b z0.b, p0/z, [src, 0, mul vl] ++ ld1b z1.b, p0/z, [src, 1, mul vl] ++ st1b z2.b, p0, [dst, 2, mul vl] ++ st1b z3.b, p0, [dst, 3, mul vl] ++ ld1b z2.b, p0/z, [src, 2, mul vl] ++ ld1b z3.b, p0/z, [src, 3, mul vl] + .endm + + .macro stld1b_unroll4b +- st1b z4.b, p0, [dest_ptr, #4, mul vl] +- st1b z5.b, p0, [dest_ptr, #5, mul vl] +- ld1b z4.b, p0/z, [src_ptr, #4, mul vl] +- ld1b z5.b, p0/z, [src_ptr, #5, mul vl] +- st1b z6.b, p0, [dest_ptr, #6, mul vl] +- st1b z7.b, p0, [dest_ptr, #7, mul vl] +- ld1b z6.b, p0/z, [src_ptr, #6, mul vl] +- ld1b z7.b, p0/z, [src_ptr, #7, mul vl] ++ st1b z4.b, p0, [dst, 4, mul vl] ++ st1b z5.b, p0, [dst, 5, mul vl] ++ ld1b z4.b, p0/z, [src, 4, mul vl] ++ ld1b z5.b, p0/z, [src, 5, mul vl] ++ st1b z6.b, p0, [dst, 6, mul vl] ++ st1b z7.b, p0, [dst, 7, mul vl] ++ ld1b z6.b, p0/z, [src, 6, mul vl] ++ ld1b z7.b, p0/z, [src, 7, mul vl] + .endm + + .macro stld1b_unroll8 +@@ -97,87 +84,18 @@ + .endm + + .macro st1b_unroll8 +- st1b z0.b, p0, [dest_ptr, #0, mul vl] +- st1b z1.b, p0, [dest_ptr, #1, mul vl] +- st1b z2.b, p0, [dest_ptr, #2, mul vl] +- st1b z3.b, p0, [dest_ptr, #3, mul vl] +- st1b z4.b, p0, [dest_ptr, #4, mul vl] +- st1b z5.b, p0, [dest_ptr, #5, mul vl] +- st1b z6.b, p0, [dest_ptr, #6, mul vl] +- st1b z7.b, p0, [dest_ptr, #7, mul vl] ++ st1b z0.b, p0, [dst, 0, mul vl] ++ st1b z1.b, p0, [dst, 1, mul vl] ++ st1b z2.b, p0, [dst, 2, mul vl] ++ st1b z3.b, p0, [dst, 3, mul vl] ++ st1b z4.b, p0, [dst, 4, mul vl] ++ st1b z5.b, p0, [dst, 5, mul vl] ++ st1b z6.b, p0, [dst, 6, mul vl] ++ st1b z7.b, p0, [dst, 7, mul vl] + .endm + +- .macro shortcut_for_small_size exit +- // if rest <= vector_length * 2 +- whilelo p0.b, xzr, n +- whilelo p1.b, vector_length, n +- b.last 1f +- ld1b z0.b, p0/z, [src, #0, mul vl] +- ld1b z1.b, p1/z, [src, #1, mul vl] +- st1b z0.b, p0, [dest, #0, mul vl] +- st1b z1.b, p1, [dest, #1, mul vl] +- ret +-1: // if rest > vector_length * 8 +- cmp n, vector_length, lsl 3 // vector_length * 8 +- b.hi \exit +- // if rest <= vector_length * 4 +- lsl tmp1, vector_length, 1 // vector_length * 2 +- whilelo p2.b, tmp1, n +- incb tmp1 +- whilelo p3.b, tmp1, n +- b.last 1f +- ld1b z0.b, p0/z, [src, #0, mul vl] +- ld1b z1.b, p1/z, [src, #1, mul vl] +- ld1b z2.b, p2/z, [src, #2, mul vl] +- ld1b z3.b, p3/z, [src, #3, mul vl] +- st1b z0.b, p0, [dest, #0, mul vl] +- st1b z1.b, p1, [dest, #1, mul vl] +- st1b z2.b, p2, [dest, #2, mul vl] +- st1b z3.b, p3, [dest, #3, mul vl] +- ret +-1: // if rest <= vector_length * 8 +- lsl tmp1, vector_length, 2 // vector_length * 4 +- whilelo p4.b, tmp1, n +- incb tmp1 +- whilelo p5.b, tmp1, n +- b.last 1f +- ld1b z0.b, p0/z, [src, #0, mul vl] +- ld1b z1.b, p1/z, [src, #1, mul vl] +- ld1b z2.b, p2/z, [src, #2, mul vl] +- ld1b z3.b, p3/z, [src, #3, mul vl] +- ld1b z4.b, p4/z, [src, #4, mul vl] +- ld1b z5.b, p5/z, [src, #5, mul vl] +- st1b z0.b, p0, [dest, #0, mul vl] +- st1b z1.b, p1, [dest, #1, mul vl] +- st1b z2.b, p2, [dest, #2, mul vl] +- st1b z3.b, p3, [dest, #3, mul vl] +- st1b z4.b, p4, [dest, #4, mul vl] +- st1b z5.b, p5, [dest, #5, mul vl] +- ret +-1: lsl tmp1, vector_length, 2 // vector_length * 4 +- incb tmp1 // vector_length * 5 +- incb tmp1 // vector_length * 6 +- whilelo p6.b, tmp1, n +- incb tmp1 +- whilelo p7.b, tmp1, n +- ld1b z0.b, p0/z, [src, #0, mul vl] +- ld1b z1.b, p1/z, [src, #1, mul vl] +- ld1b z2.b, p2/z, [src, #2, mul vl] +- ld1b z3.b, p3/z, [src, #3, mul vl] +- ld1b z4.b, p4/z, [src, #4, mul vl] +- ld1b z5.b, p5/z, [src, #5, mul vl] +- ld1b z6.b, p6/z, [src, #6, mul vl] +- ld1b z7.b, p7/z, [src, #7, mul vl] +- st1b z0.b, p0, [dest, #0, mul vl] +- st1b z1.b, p1, [dest, #1, mul vl] +- st1b z2.b, p2, [dest, #2, mul vl] +- st1b z3.b, p3, [dest, #3, mul vl] +- st1b z4.b, p4, [dest, #4, mul vl] +- st1b z5.b, p5, [dest, #5, mul vl] +- st1b z6.b, p6, [dest, #6, mul vl] +- st1b z7.b, p7, [dest, #7, mul vl] +- ret +- .endm ++#undef BTI_C ++#define BTI_C + + ENTRY (MEMCPY) + +@@ -185,223 +103,209 @@ ENTRY (MEMCPY) + PTR_ARG (1) + SIZE_ARG (2) + +-L(memcpy): +- cntb vector_length +- // shortcut for less than vector_length * 8 +- // gives a free ptrue to p0.b for n >= vector_length +- shortcut_for_small_size L(vl_agnostic) +- // end of shortcut +- +-L(vl_agnostic): // VL Agnostic +- mov rest, n +- mov dest_ptr, dest +- mov src_ptr, src +- // if rest >= L2_SIZE && vector_length == 64 then L(L2) +- mov tmp1, 64 +- cmp rest, L2_SIZE +- ccmp vector_length, tmp1, 0, cs +- b.eq L(L2) +- +-L(unroll8): // unrolling and software pipeline +- lsl tmp1, vector_length, 3 // vector_length * 8 +- .p2align 3 +- cmp rest, tmp1 +- b.cc L(last) ++ cntb vlen ++ cmp n, vlen, lsl 1 ++ b.hi L(copy_small) ++ whilelo p1.b, vlen, n ++ whilelo p0.b, xzr, n ++ ld1b z0.b, p0/z, [src, 0, mul vl] ++ ld1b z1.b, p1/z, [src, 1, mul vl] ++ st1b z0.b, p0, [dstin, 0, mul vl] ++ st1b z1.b, p1, [dstin, 1, mul vl] ++ ret ++ ++ .p2align 4 ++ ++L(copy_small): ++ cmp n, vlen, lsl 3 ++ b.hi L(copy_large) ++ add dstend, dstin, n ++ add srcend, src, n ++ cmp n, vlen, lsl 2 ++ b.hi 1f ++ ++ /* Copy 2-4 vectors. */ ++ ptrue p0.b ++ ld1b z0.b, p0/z, [src, 0, mul vl] ++ ld1b z1.b, p0/z, [src, 1, mul vl] ++ ld1b z2.b, p0/z, [srcend, -2, mul vl] ++ ld1b z3.b, p0/z, [srcend, -1, mul vl] ++ st1b z0.b, p0, [dstin, 0, mul vl] ++ st1b z1.b, p0, [dstin, 1, mul vl] ++ st1b z2.b, p0, [dstend, -2, mul vl] ++ st1b z3.b, p0, [dstend, -1, mul vl] ++ ret ++ ++ .p2align 4 ++ /* Copy 4-8 vectors. */ ++1: ptrue p0.b ++ ld1b z0.b, p0/z, [src, 0, mul vl] ++ ld1b z1.b, p0/z, [src, 1, mul vl] ++ ld1b z2.b, p0/z, [src, 2, mul vl] ++ ld1b z3.b, p0/z, [src, 3, mul vl] ++ ld1b z4.b, p0/z, [srcend, -4, mul vl] ++ ld1b z5.b, p0/z, [srcend, -3, mul vl] ++ ld1b z6.b, p0/z, [srcend, -2, mul vl] ++ ld1b z7.b, p0/z, [srcend, -1, mul vl] ++ st1b z0.b, p0, [dstin, 0, mul vl] ++ st1b z1.b, p0, [dstin, 1, mul vl] ++ st1b z2.b, p0, [dstin, 2, mul vl] ++ st1b z3.b, p0, [dstin, 3, mul vl] ++ st1b z4.b, p0, [dstend, -4, mul vl] ++ st1b z5.b, p0, [dstend, -3, mul vl] ++ st1b z6.b, p0, [dstend, -2, mul vl] ++ st1b z7.b, p0, [dstend, -1, mul vl] ++ ret ++ ++ .p2align 4 ++ /* At least 8 vectors - always align to vector length for ++ higher and consistent write performance. */ ++L(copy_large): ++ sub tmp, vlen, 1 ++ and tmp, dstin, tmp ++ sub tmp, vlen, tmp ++ whilelo p1.b, xzr, tmp ++ ld1b z1.b, p1/z, [src] ++ st1b z1.b, p1, [dstin] ++ add dst, dstin, tmp ++ add src, src, tmp ++ sub n, n, tmp ++ ptrue p0.b ++ ++ lsl vlen8, vlen, 3 ++ subs n, n, vlen8 ++ b.ls 3f + ld1b_unroll8 +- add src_ptr, src_ptr, tmp1 +- sub rest, rest, tmp1 +- cmp rest, tmp1 +- b.cc 2f +- .p2align 3 ++ add src, src, vlen8 ++ subs n, n, vlen8 ++ b.ls 2f ++ ++ .p2align 4 ++ /* 8x unrolled and software pipelined loop. */ + 1: stld1b_unroll8 +- add dest_ptr, dest_ptr, tmp1 +- add src_ptr, src_ptr, tmp1 +- sub rest, rest, tmp1 +- cmp rest, tmp1 +- b.ge 1b ++ add dst, dst, vlen8 ++ add src, src, vlen8 ++ subs n, n, vlen8 ++ b.hi 1b + 2: st1b_unroll8 +- add dest_ptr, dest_ptr, tmp1 +- +- .p2align 3 +-L(last): +- whilelo p0.b, xzr, rest +- whilelo p1.b, vector_length, rest +- b.last 1f +- ld1b z0.b, p0/z, [src_ptr, #0, mul vl] +- ld1b z1.b, p1/z, [src_ptr, #1, mul vl] +- st1b z0.b, p0, [dest_ptr, #0, mul vl] +- st1b z1.b, p1, [dest_ptr, #1, mul vl] +- ret +-1: lsl tmp1, vector_length, 1 // vector_length * 2 +- whilelo p2.b, tmp1, rest +- incb tmp1 +- whilelo p3.b, tmp1, rest +- b.last 1f +- ld1b z0.b, p0/z, [src_ptr, #0, mul vl] +- ld1b z1.b, p1/z, [src_ptr, #1, mul vl] +- ld1b z2.b, p2/z, [src_ptr, #2, mul vl] +- ld1b z3.b, p3/z, [src_ptr, #3, mul vl] +- st1b z0.b, p0, [dest_ptr, #0, mul vl] +- st1b z1.b, p1, [dest_ptr, #1, mul vl] +- st1b z2.b, p2, [dest_ptr, #2, mul vl] +- st1b z3.b, p3, [dest_ptr, #3, mul vl] ++ add dst, dst, vlen8 ++3: add n, n, vlen8 ++ ++ /* Move last 0-8 vectors. */ ++L(last_bytes): ++ cmp n, vlen, lsl 1 ++ b.hi 1f ++ whilelo p0.b, xzr, n ++ whilelo p1.b, vlen, n ++ ld1b z0.b, p0/z, [src, 0, mul vl] ++ ld1b z1.b, p1/z, [src, 1, mul vl] ++ st1b z0.b, p0, [dst, 0, mul vl] ++ st1b z1.b, p1, [dst, 1, mul vl] + ret +-1: lsl tmp1, vector_length, 2 // vector_length * 4 +- whilelo p4.b, tmp1, rest +- incb tmp1 +- whilelo p5.b, tmp1, rest +- incb tmp1 +- whilelo p6.b, tmp1, rest +- incb tmp1 +- whilelo p7.b, tmp1, rest +- ld1b z0.b, p0/z, [src_ptr, #0, mul vl] +- ld1b z1.b, p1/z, [src_ptr, #1, mul vl] +- ld1b z2.b, p2/z, [src_ptr, #2, mul vl] +- ld1b z3.b, p3/z, [src_ptr, #3, mul vl] +- ld1b z4.b, p4/z, [src_ptr, #4, mul vl] +- ld1b z5.b, p5/z, [src_ptr, #5, mul vl] +- ld1b z6.b, p6/z, [src_ptr, #6, mul vl] +- ld1b z7.b, p7/z, [src_ptr, #7, mul vl] +- st1b z0.b, p0, [dest_ptr, #0, mul vl] +- st1b z1.b, p1, [dest_ptr, #1, mul vl] +- st1b z2.b, p2, [dest_ptr, #2, mul vl] +- st1b z3.b, p3, [dest_ptr, #3, mul vl] +- st1b z4.b, p4, [dest_ptr, #4, mul vl] +- st1b z5.b, p5, [dest_ptr, #5, mul vl] +- st1b z6.b, p6, [dest_ptr, #6, mul vl] +- st1b z7.b, p7, [dest_ptr, #7, mul vl] ++ ++ .p2align 4 ++ ++1: add srcend, src, n ++ add dstend, dst, n ++ ld1b z0.b, p0/z, [src, 0, mul vl] ++ ld1b z1.b, p0/z, [src, 1, mul vl] ++ ld1b z2.b, p0/z, [srcend, -2, mul vl] ++ ld1b z3.b, p0/z, [srcend, -1, mul vl] ++ cmp n, vlen, lsl 2 ++ b.hi 1f ++ ++ st1b z0.b, p0, [dst, 0, mul vl] ++ st1b z1.b, p0, [dst, 1, mul vl] ++ st1b z2.b, p0, [dstend, -2, mul vl] ++ st1b z3.b, p0, [dstend, -1, mul vl] + ret + +-L(L2): +- // align dest address at CACHE_LINE_SIZE byte boundary +- mov tmp1, CACHE_LINE_SIZE +- ands tmp2, dest_ptr, CACHE_LINE_SIZE - 1 +- // if cl_remainder == 0 +- b.eq L(L2_dc_zva) +- sub cl_remainder, tmp1, tmp2 +- // process remainder until the first CACHE_LINE_SIZE boundary +- whilelo p1.b, xzr, cl_remainder // keep p0.b all true +- whilelo p2.b, vector_length, cl_remainder +- b.last 1f +- ld1b z1.b, p1/z, [src_ptr, #0, mul vl] +- ld1b z2.b, p2/z, [src_ptr, #1, mul vl] +- st1b z1.b, p1, [dest_ptr, #0, mul vl] +- st1b z2.b, p2, [dest_ptr, #1, mul vl] +- b 2f +-1: lsl tmp1, vector_length, 1 // vector_length * 2 +- whilelo p3.b, tmp1, cl_remainder +- incb tmp1 +- whilelo p4.b, tmp1, cl_remainder +- ld1b z1.b, p1/z, [src_ptr, #0, mul vl] +- ld1b z2.b, p2/z, [src_ptr, #1, mul vl] +- ld1b z3.b, p3/z, [src_ptr, #2, mul vl] +- ld1b z4.b, p4/z, [src_ptr, #3, mul vl] +- st1b z1.b, p1, [dest_ptr, #0, mul vl] +- st1b z2.b, p2, [dest_ptr, #1, mul vl] +- st1b z3.b, p3, [dest_ptr, #2, mul vl] +- st1b z4.b, p4, [dest_ptr, #3, mul vl] +-2: add dest_ptr, dest_ptr, cl_remainder +- add src_ptr, src_ptr, cl_remainder +- sub rest, rest, cl_remainder +- +-L(L2_dc_zva): +- // zero fill +- and tmp1, dest, 0xffffffffffffff +- and tmp2, src, 0xffffffffffffff +- subs tmp1, tmp1, tmp2 // diff +- b.ge 1f +- neg tmp1, tmp1 +-1: mov tmp3, ZF_DIST + CACHE_LINE_SIZE * 2 +- cmp tmp1, tmp3 +- b.lo L(unroll8) +- mov tmp1, dest_ptr +- dc_zva (ZF_DIST / CACHE_LINE_SIZE) - 1 +- // unroll +- ld1b_unroll8 // this line has to be after "b.lo L(unroll8)" +- add src_ptr, src_ptr, CACHE_LINE_SIZE * 2 +- sub rest, rest, CACHE_LINE_SIZE * 2 +- mov tmp1, ZF_DIST +- .p2align 3 +-1: stld1b_unroll4a +- add tmp2, dest_ptr, tmp1 // dest_ptr + ZF_DIST +- dc zva, tmp2 +- stld1b_unroll4b +- add tmp2, tmp2, CACHE_LINE_SIZE +- dc zva, tmp2 +- add dest_ptr, dest_ptr, CACHE_LINE_SIZE * 2 +- add src_ptr, src_ptr, CACHE_LINE_SIZE * 2 +- sub rest, rest, CACHE_LINE_SIZE * 2 +- cmp rest, tmp3 // ZF_DIST + CACHE_LINE_SIZE * 2 +- b.ge 1b +- st1b_unroll8 +- add dest_ptr, dest_ptr, CACHE_LINE_SIZE * 2 +- b L(unroll8) ++1: ld1b z4.b, p0/z, [src, 2, mul vl] ++ ld1b z5.b, p0/z, [src, 3, mul vl] ++ ld1b z6.b, p0/z, [srcend, -4, mul vl] ++ ld1b z7.b, p0/z, [srcend, -3, mul vl] ++ st1b z0.b, p0, [dst, 0, mul vl] ++ st1b z1.b, p0, [dst, 1, mul vl] ++ st1b z4.b, p0, [dst, 2, mul vl] ++ st1b z5.b, p0, [dst, 3, mul vl] ++ st1b z6.b, p0, [dstend, -4, mul vl] ++ st1b z7.b, p0, [dstend, -3, mul vl] ++ st1b z2.b, p0, [dstend, -2, mul vl] ++ st1b z3.b, p0, [dstend, -1, mul vl] ++ ret + + END (MEMCPY) + libc_hidden_builtin_def (MEMCPY) + + +-ENTRY (MEMMOVE) ++ENTRY_ALIGN (MEMMOVE, 4) + + PTR_ARG (0) + PTR_ARG (1) + SIZE_ARG (2) + +- // remove tag address +- // dest has to be immutable because it is the return value +- // src has to be immutable because it is used in L(bwd_last) +- and tmp2, dest, 0xffffffffffffff // save dest_notag into tmp2 +- and tmp3, src, 0xffffffffffffff // save src_notag intp tmp3 +- cmp n, 0 +- ccmp tmp2, tmp3, 4, ne +- b.ne 1f ++ /* Fast case for up to 2 vectors. */ ++ cntb vlen ++ cmp n, vlen, lsl 1 ++ b.hi 1f ++ whilelo p0.b, xzr, n ++ whilelo p1.b, vlen, n ++ ld1b z0.b, p0/z, [src, 0, mul vl] ++ ld1b z1.b, p1/z, [src, 1, mul vl] ++ st1b z0.b, p0, [dstin, 0, mul vl] ++ st1b z1.b, p1, [dstin, 1, mul vl] ++L(full_overlap): + ret +-1: cntb vector_length +- // shortcut for less than vector_length * 8 +- // gives a free ptrue to p0.b for n >= vector_length +- // tmp2 and tmp3 should not be used in this macro to keep +- // notag addresses +- shortcut_for_small_size L(dispatch) +- // end of shortcut +- +-L(dispatch): +- // tmp2 = dest_notag, tmp3 = src_notag +- // diff = dest_notag - src_notag +- sub tmp1, tmp2, tmp3 +- // if diff <= 0 || diff >= n then memcpy +- cmp tmp1, 0 +- ccmp tmp1, n, 2, gt +- b.cs L(vl_agnostic) +- +-L(bwd_start): +- mov rest, n +- add dest_ptr, dest, n // dest_end +- add src_ptr, src, n // src_end +- +-L(bwd_unroll8): // unrolling and software pipeline +- lsl tmp1, vector_length, 3 // vector_length * 8 +- .p2align 3 +- cmp rest, tmp1 +- b.cc L(bwd_last) +- sub src_ptr, src_ptr, tmp1 ++ ++ .p2align 4 ++ /* Check for overlapping moves. Return if there is a full overlap. ++ Small moves up to 8 vectors use the overlap-safe copy_small code. ++ Non-overlapping or overlapping moves with dst < src use memcpy. ++ Overlapping moves with dst > src use a backward copy loop. */ ++1: sub tmp, dstin, src ++ ands tmp, tmp, 0xffffffffffffff /* Clear special tag bits. */ ++ b.eq L(full_overlap) ++ cmp n, vlen, lsl 3 ++ b.ls L(copy_small) ++ cmp tmp, n ++ b.hs L(copy_large) ++ ++ /* Align to vector length. */ ++ add dst, dstin, n ++ sub tmp, vlen, 1 ++ ands tmp, dst, tmp ++ csel tmp, tmp, vlen, ne ++ whilelo p1.b, xzr, tmp ++ sub n, n, tmp ++ ld1b z1.b, p1/z, [src, n] ++ st1b z1.b, p1, [dstin, n] ++ add src, src, n ++ add dst, dstin, n ++ ++ ptrue p0.b ++ lsl vlen8, vlen, 3 ++ subs n, n, vlen8 ++ b.ls 3f ++ sub src, src, vlen8 + ld1b_unroll8 +- sub rest, rest, tmp1 +- cmp rest, tmp1 +- b.cc 2f +- .p2align 3 +-1: sub src_ptr, src_ptr, tmp1 +- sub dest_ptr, dest_ptr, tmp1 ++ subs n, n, vlen8 ++ b.ls 2f ++ ++ .p2align 4 ++ /* 8x unrolled and software pipelined backward copy loop. */ ++1: sub src, src, vlen8 ++ sub dst, dst, vlen8 + stld1b_unroll8 +- sub rest, rest, tmp1 +- cmp rest, tmp1 +- b.ge 1b +-2: sub dest_ptr, dest_ptr, tmp1 ++ subs n, n, vlen8 ++ b.hi 1b ++2: sub dst, dst, vlen8 + st1b_unroll8 ++3: add n, n, vlen8 + +-L(bwd_last): +- mov dest_ptr, dest +- mov src_ptr, src +- b L(last) ++ /* Adjust src/dst for last 0-8 vectors. */ ++ sub src, src, n ++ mov dst, dstin ++ b L(last_bytes) + + END (MEMMOVE) + libc_hidden_builtin_def (MEMMOVE) +-- +2.31.1 + diff --git a/SOURCES/glibc-rh2047981-1.patch b/SOURCES/glibc-rh2047981-1.patch new file mode 100644 index 0000000..e1a085d --- /dev/null +++ b/SOURCES/glibc-rh2047981-1.patch @@ -0,0 +1,98 @@ +commit eb77a1fccc7e60cea32245c11288c7f1d92545fa +Author: Florian Weimer +Date: Wed Oct 16 18:19:51 2019 +0200 + + dlfcn: Remove remnants of caller sensitivity from dlinfo + + dlinfo operates on a specific handle, which means that there is no + caller sensivity involved. + +diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c +index 964572cc670ceba4..23ef3f57ca41afdf 100644 +--- a/dlfcn/dlinfo.c ++++ b/dlfcn/dlinfo.c +@@ -26,7 +26,7 @@ + int + dlinfo (void *handle, int request, void *arg) + { +- return __dlinfo (handle, request, arg, RETURN_ADDRESS (0)); ++ return __dlinfo (handle, request, arg); + } + + #else +@@ -35,7 +35,6 @@ dlinfo (void *handle, int request, void *arg) + + struct dlinfo_args + { +- ElfW(Addr) caller; + void *handle; + int request; + void *arg; +@@ -47,24 +46,6 @@ dlinfo_doit (void *argsblock) + struct dlinfo_args *const args = argsblock; + struct link_map *l = args->handle; + +-# if 0 +- if (args->handle == RTLD_SELF) +- { +- Lmid_t nsid; +- +- /* Find the highest-addressed object that CALLER is not below. */ +- for (nsid = 0; nsid < DL_NNS; ++nsid) +- for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next) +- if (caller >= l->l_map_start && caller < l->l_map_end +- && (l->l_contiguous || _dl_addr_inside_object (l, caller))) +- break; +- +- if (l == NULL) +- _dl_signal_error (0, NULL, NULL, N_("\ +-RTLD_SELF used in code not dynamically loaded")); +- } +-# endif +- + switch (args->request) + { + case RTLD_DI_CONFIGADDR: +@@ -108,16 +89,14 @@ RTLD_SELF used in code not dynamically loaded")); + } + + int +-__dlinfo (void *handle, int request, void *arg DL_CALLER_DECL) ++__dlinfo (void *handle, int request, void *arg) + { + # ifdef SHARED + if (!rtld_active ()) +- return _dlfcn_hook->dlinfo (handle, request, arg, +- DL_CALLER); ++ return _dlfcn_hook->dlinfo (handle, request, arg); + # endif + +- struct dlinfo_args args = { (ElfW(Addr)) DL_CALLER, +- handle, request, arg }; ++ struct dlinfo_args args = { handle, request, arg }; + return _dlerror_run (&dlinfo_doit, &args) ? -1 : 0; + } + # ifdef SHARED +diff --git a/include/dlfcn.h b/include/dlfcn.h +index 0dc57dbe2217cfe7..93dd369ab12a5745 100644 +--- a/include/dlfcn.h ++++ b/include/dlfcn.h +@@ -117,7 +117,7 @@ struct dlfcn_hook + int (*dladdr) (const void *address, Dl_info *info); + int (*dladdr1) (const void *address, Dl_info *info, + void **extra_info, int flags); +- int (*dlinfo) (void *handle, int request, void *arg, void *dl_caller); ++ int (*dlinfo) (void *handle, int request, void *arg); + void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller); + void *pad[4]; + }; +@@ -143,8 +143,7 @@ extern int __dladdr (const void *address, Dl_info *info) + extern int __dladdr1 (const void *address, Dl_info *info, + void **extra_info, int flags) + attribute_hidden; +-extern int __dlinfo (void *handle, int request, void *arg DL_CALLER_DECL) +- attribute_hidden; ++extern int __dlinfo (void *handle, int request, void *arg) attribute_hidden; + + #ifndef SHARED + struct link_map; diff --git a/SOURCES/glibc-rh2047981-10.patch b/SOURCES/glibc-rh2047981-10.patch new file mode 100644 index 0000000..00b7a71 --- /dev/null +++ b/SOURCES/glibc-rh2047981-10.patch @@ -0,0 +1,31 @@ +commit 88361b408b9dbd313f15413cc2e6be0f1cafb01a +Author: H.J. Lu +Date: Tue Aug 17 19:36:04 2021 -0700 + + elf: Copy l_addr/l_ld when adding ld.so to a new namespace + + When add ld.so to a new namespace, we don't actually load ld.so. We + create a new link map and refers the real one for almost everything. + Copy l_addr and l_ld from the real ld.so link map to avoid GDB warning: + + warning: .dynamic section for ".../elf/ld-linux-x86-64.so.2" is not at the expected address (wrong library or version mismatch?) + + when handling shared library loaded by dlmopen. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index cdb5d4b5b67f1ca1..303e6594f9af9b7e 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -932,6 +932,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + /* Refer to the real descriptor. */ + l->l_real = &GL(dl_rtld_map); + ++ /* Copy l_addr and l_ld to avoid a GDB warning with dlmopen(). */ ++ l->l_addr = l->l_real->l_addr; ++ l->l_ld = l->l_real->l_ld; ++ + /* No need to bump the refcount of the real object, ld.so will + never be unloaded. */ + __close_nocancel (fd); diff --git a/SOURCES/glibc-rh2047981-11.patch b/SOURCES/glibc-rh2047981-11.patch new file mode 100644 index 0000000..a0cde6c --- /dev/null +++ b/SOURCES/glibc-rh2047981-11.patch @@ -0,0 +1,45 @@ +commit 1e1ecea62e899acb58c3fdf3b320a0833ddd0dff +Author: H.J. Lu +Date: Thu Sep 30 10:29:17 2021 -0700 + + elf: Replace nsid with args.nsid [BZ #27609] + + commit ec935dea6332cb22f9881cd1162bad156173f4b0 + Author: Florian Weimer + Date: Fri Apr 24 22:31:15 2020 +0200 + + elf: Implement __libc_early_init + + has + + @@ -856,6 +876,11 @@ no more namespaces available for dlmopen()")); + /* See if an error occurred during loading. */ + if (__glibc_unlikely (exception.errstring != NULL)) + { + + /* Avoid keeping around a dangling reference to the libc.so link + + map in case it has been cached in libc_map. */ + + if (!args.libc_already_loaded) + + GL(dl_ns)[nsid].libc_map = NULL; + + + + do_dlopen calls _dl_open with nsid == __LM_ID_CALLER (-2), which calls + dl_open_worker with args.nsid = nsid. dl_open_worker updates args.nsid + if it is __LM_ID_CALLER. After dl_open_worker returns, it is wrong to + use nsid. + + Replace nsid with args.nsid after dl_open_worker returns. This fixes + BZ #27609. + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 661a2172d1789b26..b5a4da04907d8d29 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -916,7 +916,7 @@ no more namespaces available for dlmopen()")); + /* Avoid keeping around a dangling reference to the libc.so link + map in case it has been cached in libc_map. */ + if (!args.libc_already_loaded) +- GL(dl_ns)[nsid].libc_map = NULL; ++ GL(dl_ns)[args.nsid].libc_map = NULL; + + /* Remove the object from memory. It may be in an inconsistent + state if relocation failed, for example. */ diff --git a/SOURCES/glibc-rh2047981-12.patch b/SOURCES/glibc-rh2047981-12.patch new file mode 100644 index 0000000..8588aaa --- /dev/null +++ b/SOURCES/glibc-rh2047981-12.patch @@ -0,0 +1,607 @@ +This is a partial backport of this commit with only the 'scope' +refactoring required to have access to the outer scope value +to use with RESOLVE_MAP to implement la_symbind for BIND_NOW. + +We do not backport this entire patch because the nested function +changes have significant impact on code generation and would +require furhter backports to support and maintain. + +commit 490e6c62aa31a8aa5c4a059f6e646ede121edf0a +Author: Fangrui Song +Date: Thu Oct 7 11:55:02 2021 -0700 + + elf: Avoid nested functions in the loader [BZ #27220] + + dynamic-link.h is included more than once in some elf/ files (rtld.c, + dl-conflict.c, dl-reloc.c, dl-reloc-static-pie.c) and uses GCC nested + functions. This harms readability and the nested functions usage + is the biggest obstacle prevents Clang build (Clang doesn't support GCC + nested functions). + + The key idea for unnesting is to add extra parameters (struct link_map + *and struct r_scope_elm *[]) to RESOLVE_MAP, + ELF_MACHINE_BEFORE_RTLD_RELOC, ELF_DYNAMIC_RELOCATE, elf_machine_rel[a], + elf_machine_lazy_rel, and elf_machine_runtime_setup. (This is inspired + by Stan Shebs' ppc64/x86-64 implementation in the + google/grte/v5-2.27/master which uses mixed extra parameters and static + variables.) + + Future simplification: + * If mips elf_machine_runtime_setup no longer needs RESOLVE_GOTSYM, + elf_machine_runtime_setup can drop the `scope` parameter. + * If TLSDESC no longer need to be in elf_machine_lazy_rel, + elf_machine_lazy_rel can drop the `scope` parameter. + + Tested on aarch64, i386, x86-64, powerpc64le, powerpc64, powerpc32, + sparc64, sparcv9, s390x, s390, hppa, ia64, armhf, alpha, and mips64. + In addition, tested build-many-glibcs.py with {arc,csky,microblaze,nios2}-linux-gnu + and riscv64-linux-gnu-rv64imafdc-lp64d. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-conflict.c b/elf/dl-conflict.c +index 70f14b04cd383048..31d87ac846427752 100644 +--- a/elf/dl-conflict.c ++++ b/elf/dl-conflict.c +@@ -40,7 +40,7 @@ _dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict, + data. */ + + /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */ +-#define RESOLVE_MAP(ref, version, flags) (*ref = NULL, NULL) ++#define RESOLVE_MAP(map, scope, ref, version, flags) (*ref = NULL, NULL) + #define RESOLVE(ref, version, flags) (*ref = NULL, 0) + #define RESOLVE_CONFLICT_FIND_MAP(map, r_offset) \ + do { \ +@@ -67,8 +67,8 @@ _dl_resolve_conflicts (struct link_map *l, ElfW(Rela) *conflict, + GL(dl_num_cache_relocations) += conflictend - conflict; + + for (; conflict < conflictend; ++conflict) +- elf_machine_rela (l, conflict, NULL, NULL, (void *) conflict->r_offset, +- 0); ++ elf_machine_rela (l, NULL, conflict, NULL, NULL, ++ (void *) conflict->r_offset, 0); + } + #endif + } +diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c +index ab1ce0eacced9d2b..1efbf515c3c1c16d 100644 +--- a/elf/dl-reloc-static-pie.c ++++ b/elf/dl-reloc-static-pie.c +@@ -30,7 +30,7 @@ _dl_relocate_static_pie (void) + + # define STATIC_PIE_BOOTSTRAP + # define BOOTSTRAP_MAP (main_map) +-# define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP ++# define RESOLVE_MAP(map, scope, sym, version, flags) BOOTSTRAP_MAP + # include "dynamic-link.h" + + /* Figure out the run-time load address of static PIE. */ +@@ -46,7 +46,7 @@ _dl_relocate_static_pie (void) + + /* Relocate ourselves so we can do normal function calls and + data access using the global offset table. */ +- ELF_DYNAMIC_RELOCATE (main_map, 0, 0, 0); ++ ELF_DYNAMIC_RELOCATE (main_map, NULL, 0, 0, 0); + main_map->l_relocated = 1; + + /* Initialize _r_debug. */ +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index c6139b89d4ecddc8..19de5de067a5ef07 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -250,7 +250,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + + /* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */ +-#define RESOLVE_MAP(ref, version, r_type) \ ++#define RESOLVE_MAP(l, scope, ref, version, r_type) \ + ((ELFW(ST_BIND) ((*ref)->st_info) != STB_LOCAL \ + && __glibc_likely (!dl_symbol_visibility_binds_local_p (*ref))) \ + ? ((__builtin_expect ((*ref) == l->l_lookup_cache.sym, 0) \ +@@ -275,7 +275,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + + #include "dynamic-link.h" + +- ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling, skip_ifunc); ++ ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc); + + #ifndef PROF + if (__glibc_unlikely (consider_profiling) +diff --git a/elf/do-rel.h b/elf/do-rel.h +index 19cb5d236ee30698..0b04d1a0bf28b9f4 100644 +--- a/elf/do-rel.h ++++ b/elf/do-rel.h +@@ -38,7 +38,7 @@ + than fully resolved now. */ + + auto inline void __attribute__ ((always_inline)) +-elf_dynamic_do_Rel (struct link_map *map, ++elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[], + ElfW(Addr) reladdr, ElfW(Addr) relsize, + __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative, + int lazy, int skip_ifunc) +@@ -68,13 +68,13 @@ elf_dynamic_do_Rel (struct link_map *map, + } + else + # endif +- elf_machine_lazy_rel (map, l_addr, r, skip_ifunc); ++ elf_machine_lazy_rel (map, scope, l_addr, r, skip_ifunc); + + # ifdef ELF_MACHINE_IRELATIVE + if (r2 != NULL) + for (; r2 <= end2; ++r2) + if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE) +- elf_machine_lazy_rel (map, l_addr, r2, skip_ifunc); ++ elf_machine_lazy_rel (map, scope, l_addr, r2, skip_ifunc); + # endif + } + else +@@ -134,7 +134,7 @@ elf_dynamic_do_Rel (struct link_map *map, + #endif + + ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff; +- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], ++ elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], + &map->l_versions[ndx], + (void *) (l_addr + r->r_offset), skip_ifunc); + } +@@ -146,7 +146,7 @@ elf_dynamic_do_Rel (struct link_map *map, + { + ElfW(Half) ndx + = version[ELFW(R_SYM) (r2->r_info)] & 0x7fff; +- elf_machine_rel (map, r2, ++ elf_machine_rel (map, scope, r2, + &symtab[ELFW(R_SYM) (r2->r_info)], + &map->l_versions[ndx], + (void *) (l_addr + r2->r_offset), +@@ -167,14 +167,14 @@ elf_dynamic_do_Rel (struct link_map *map, + } + else + # endif +- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, ++ elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, + (void *) (l_addr + r->r_offset), skip_ifunc); + + # ifdef ELF_MACHINE_IRELATIVE + if (r2 != NULL) + for (; r2 <= end2; ++r2) + if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE) +- elf_machine_rel (map, r2, &symtab[ELFW(R_SYM) (r2->r_info)], ++ elf_machine_rel (map, scope, r2, &symtab[ELFW(R_SYM) (r2->r_info)], + NULL, (void *) (l_addr + r2->r_offset), + skip_ifunc); + # endif +diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h +index 2fc3c91b7defe84e..357a2e3c6825e0fc 100644 +--- a/elf/dynamic-link.h ++++ b/elf/dynamic-link.h +@@ -60,8 +60,9 @@ int _dl_try_allocate_static_tls (struct link_map *map, bool optional) + unaligned cases. */ + # if ! ELF_MACHINE_NO_REL + auto inline void __attribute__((always_inline)) +-elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc, +- const ElfW(Sym) *sym, const struct r_found_version *version, ++elf_machine_rel (struct link_map *map, struct r_scope_elem *scope[], ++ const ElfW(Rel) *reloc, const ElfW(Sym) *sym, ++ const struct r_found_version *version, + void *const reloc_addr, int skip_ifunc); + auto inline void __attribute__((always_inline)) + elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc, +@@ -69,8 +70,9 @@ elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc, + # endif + # if ! ELF_MACHINE_NO_RELA + auto inline void __attribute__((always_inline)) +-elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, +- const ElfW(Sym) *sym, const struct r_found_version *version, ++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], ++ const ElfW(Rela) *reloc, const ElfW(Sym) *sym, ++ const struct r_found_version *version, + void *const reloc_addr, int skip_ifunc); + auto inline void __attribute__((always_inline)) + elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc, +@@ -78,12 +80,12 @@ elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc, + # endif + # if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL + auto inline void __attribute__((always_inline)) +-elf_machine_lazy_rel (struct link_map *map, ++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], + ElfW(Addr) l_addr, const ElfW(Rel) *reloc, + int skip_ifunc); + # else + auto inline void __attribute__((always_inline)) +-elf_machine_lazy_rel (struct link_map *map, ++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], + ElfW(Addr) l_addr, const ElfW(Rela) *reloc, + int skip_ifunc); + # endif +@@ -114,7 +116,7 @@ elf_machine_lazy_rel (struct link_map *map, + consumes precisely the very end of the DT_REL*, or DT_JMPREL and DT_REL* + are completely separate and there is a gap between them. */ + +-# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \ ++# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, test_rel) \ + do { \ + struct { ElfW(Addr) start, size; \ + __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \ +@@ -152,13 +154,13 @@ elf_machine_lazy_rel (struct link_map *map, + } \ + \ + if (ELF_DURING_STARTUP) \ +- elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, \ ++ elf_dynamic_do_##reloc ((map), scope, ranges[0].start, ranges[0].size, \ + ranges[0].nrelative, 0, skip_ifunc); \ + else \ + { \ + int ranges_index; \ + for (ranges_index = 0; ranges_index < 2; ++ranges_index) \ +- elf_dynamic_do_##reloc ((map), \ ++ elf_dynamic_do_##reloc ((map), scope, \ + ranges[ranges_index].start, \ + ranges[ranges_index].size, \ + ranges[ranges_index].nrelative, \ +@@ -175,29 +177,29 @@ elf_machine_lazy_rel (struct link_map *map, + + # if ! ELF_MACHINE_NO_REL + # include "do-rel.h" +-# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) \ +- _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, lazy, skip_ifunc, _ELF_CHECK_REL) ++# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) \ ++ _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc, _ELF_CHECK_REL) + # else +-# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) /* Nothing to do. */ ++# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) /* Nothing to do. */ + # endif + + # if ! ELF_MACHINE_NO_RELA + # define DO_RELA + # include "do-rel.h" +-# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) \ +- _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, lazy, skip_ifunc, _ELF_CHECK_REL) ++# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) \ ++ _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc, _ELF_CHECK_REL) + # else +-# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) /* Nothing to do. */ ++# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) /* Nothing to do. */ + # endif + + /* This can't just be an inline function because GCC is too dumb + to inline functions containing inlines themselves. */ +-# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile, skip_ifunc) \ ++# define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \ + do { \ +- int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \ ++ int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \ + (consider_profile)); \ +- ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc); \ +- ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc); \ ++ ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \ ++ ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc); \ + } while (0) + + #endif +diff --git a/elf/rtld.c b/elf/rtld.c +index e107af4014d43777..f3836b8a78faaf27 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -514,7 +514,7 @@ _dl_start (void *arg) + is trivial: always the map of ld.so itself. */ + #define RTLD_BOOTSTRAP + #define BOOTSTRAP_MAP (&bootstrap_map) +-#define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP ++#define RESOLVE_MAP(map, scope, sym, version, flags) BOOTSTRAP_MAP + #include "dynamic-link.h" + + #ifdef DONT_USE_BOOTSTRAP_MAP +@@ -560,7 +560,7 @@ _dl_start (void *arg) + /* Relocate ourselves so we can do normal function calls and + data access using the global offset table. */ + +- ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0, 0); ++ ELF_DYNAMIC_RELOCATE (&bootstrap_map, NULL, 0, 0, 0); + } + bootstrap_map.l_relocated = 1; + +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index 3fd3c8a265d012b1..5eab544afe2717f7 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -65,7 +65,8 @@ elf_machine_load_address (void) + entries will jump to the on-demand fixup code in dl-runtime.c. */ + + static inline int __attribute__ ((unused)) +-elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) ++elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], ++ int lazy, int profile) + { + if (l->l_info[DT_JMPREL] && lazy) + { +@@ -242,8 +243,9 @@ elf_machine_plt_value (struct link_map *map, + + auto inline void + __attribute__ ((always_inline)) +-elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, +- const ElfW(Sym) *sym, const struct r_found_version *version, ++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], ++ const ElfW(Rela) *reloc, const ElfW(Sym) *sym, ++ const struct r_found_version *version, + void *const reloc_addr_arg, int skip_ifunc) + { + ElfW(Addr) *const reloc_addr = reloc_addr_arg; +@@ -256,7 +258,8 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, + else + { + const ElfW(Sym) *const refsym = sym; +- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); ++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, ++ r_type); + ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true); + + if (sym != NULL +@@ -381,7 +384,7 @@ elf_machine_rela_relative (ElfW(Addr) l_addr, + + inline void + __attribute__ ((always_inline)) +-elf_machine_lazy_rel (struct link_map *map, ++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], + ElfW(Addr) l_addr, + const ElfW(Rela) *reloc, + int skip_ifunc) +@@ -408,7 +411,7 @@ elf_machine_lazy_rel (struct link_map *map, + (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); + version = &map->l_versions[vernum[symndx] & 0x7fff]; + } +- elf_machine_rela (map, reloc, sym, version, reloc_addr, ++ elf_machine_rela (map, scope, reloc, sym, version, reloc_addr, + skip_ifunc); + return; + } +@@ -435,7 +438,7 @@ elf_machine_lazy_rel (struct link_map *map, + + /* Always initialize TLS descriptors completely, because lazy + initialization requires synchronization at every TLS access. */ +- elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc); ++ elf_machine_rela (map, scope, reloc, sym, version, reloc_addr, skip_ifunc); + } + else if (__glibc_unlikely (r_type == AARCH64_R(IRELATIVE))) + { +diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h +index 3a30671591284d79..5ba95b9e4af49942 100644 +--- a/sysdeps/i386/dl-machine.h ++++ b/sysdeps/i386/dl-machine.h +@@ -61,7 +61,8 @@ elf_machine_load_address (void) + entries will jump to the on-demand fixup code in dl-runtime.c. */ + + static inline int __attribute__ ((unused, always_inline)) +-elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) ++elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], ++ int lazy, int profile) + { + Elf32_Addr *got; + extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden; +@@ -293,8 +294,9 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rel *reloc, + + auto inline void + __attribute ((always_inline)) +-elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, +- const Elf32_Sym *sym, const struct r_found_version *version, ++elf_machine_rel (struct link_map *map, struct r_scope_elem *scope[], ++ const Elf32_Rel *reloc, const Elf32_Sym *sym, ++ const struct r_found_version *version, + void *const reloc_addr_arg, int skip_ifunc) + { + Elf32_Addr *const reloc_addr = reloc_addr_arg; +@@ -327,7 +329,8 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, + # ifndef RTLD_BOOTSTRAP + const Elf32_Sym *const refsym = sym; + # endif +- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); ++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, ++ r_type); + Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true); + + if (sym != NULL +@@ -493,8 +496,9 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, + # ifndef RTLD_BOOTSTRAP + auto inline void + __attribute__ ((always_inline)) +-elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, +- const Elf32_Sym *sym, const struct r_found_version *version, ++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], ++ const Elf32_Rela *reloc, const Elf32_Sym *sym, ++ const struct r_found_version *version, + void *const reloc_addr_arg, int skip_ifunc) + { + Elf32_Addr *const reloc_addr = reloc_addr_arg; +@@ -507,7 +511,8 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, + # ifndef RESOLVE_CONFLICT_FIND_MAP + const Elf32_Sym *const refsym = sym; + # endif +- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); ++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, ++ r_type); + Elf32_Addr value = SYMBOL_ADDRESS (sym_map, sym, true); + + if (sym != NULL +@@ -661,7 +666,7 @@ elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc, + + auto inline void + __attribute__ ((always_inline)) +-elf_machine_lazy_rel (struct link_map *map, ++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], + Elf32_Addr l_addr, const Elf32_Rel *reloc, + int skip_ifunc) + { +@@ -696,13 +701,13 @@ elf_machine_lazy_rel (struct link_map *map, + const ElfW(Half) *const version = + (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); + ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff; +- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], ++ elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], + &map->l_versions[ndx], + (void *) (l_addr + r->r_offset), skip_ifunc); + } + # ifndef RTLD_BOOTSTRAP + else +- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, ++ elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, + (void *) (l_addr + r->r_offset), skip_ifunc); + # endif + } +@@ -721,7 +726,7 @@ elf_machine_lazy_rel (struct link_map *map, + + auto inline void + __attribute__ ((always_inline)) +-elf_machine_lazy_rela (struct link_map *map, ++elf_machine_lazy_rela (struct link_map *map, struct r_scope_elem *scope[], + Elf32_Addr l_addr, const Elf32_Rela *reloc, + int skip_ifunc) + { +@@ -745,7 +750,8 @@ elf_machine_lazy_rela (struct link_map *map, + + /* Always initialize TLS descriptors completely at load time, in + case static TLS is allocated for it that requires locking. */ +- elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc); ++ elf_machine_rela (map, scope, reloc, sym, version, reloc_addr, ++ skip_ifunc); + } + else if (__glibc_unlikely (r_type == R_386_IRELATIVE)) + { +diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h +index 99a83d0c82ea0a9c..35996bb9173da231 100644 +--- a/sysdeps/powerpc/powerpc64/dl-machine.h ++++ b/sysdeps/powerpc/powerpc64/dl-machine.h +@@ -345,7 +345,8 @@ dl_platform_init (void) + /* Set up the loaded object described by MAP so its unrelocated PLT + entries will jump to the on-demand fixup code in dl-runtime.c. */ + static inline int __attribute__ ((always_inline)) +-elf_machine_runtime_setup (struct link_map *map, int lazy, int profile) ++elf_machine_runtime_setup (struct link_map *map, struct r_scope_elem *scope[], ++ int lazy, int profile) + { + if (map->l_info[DT_JMPREL]) + { +@@ -679,7 +680,7 @@ resolve_ifunc (Elf64_Addr value, + /* Perform the relocation specified by RELOC and SYM (which is fully + resolved). MAP is the object containing the reloc. */ + auto inline void __attribute__ ((always_inline)) +-elf_machine_rela (struct link_map *map, ++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], + const Elf64_Rela *reloc, + const Elf64_Sym *sym, + const struct r_found_version *version, +@@ -707,7 +708,7 @@ elf_machine_rela (struct link_map *map, + + /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt + and STT_GNU_IFUNC. */ +- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); ++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type); + Elf64_Addr value = SYMBOL_ADDRESS (sym_map, sym, true) + reloc->r_addend; + + if (sym != NULL +@@ -1036,7 +1037,7 @@ elf_machine_rela (struct link_map *map, + } + + auto inline void __attribute__ ((always_inline)) +-elf_machine_lazy_rel (struct link_map *map, ++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], + Elf64_Addr l_addr, const Elf64_Rela *reloc, + int skip_ifunc) + { +diff --git a/sysdeps/s390/s390-64/dl-machine.h b/sysdeps/s390/s390-64/dl-machine.h +index f22db7860b4da3ec..36327c40a1972dd7 100644 +--- a/sysdeps/s390/s390-64/dl-machine.h ++++ b/sysdeps/s390/s390-64/dl-machine.h +@@ -75,7 +75,8 @@ elf_machine_load_address (void) + entries will jump to the on-demand fixup code in dl-runtime.c. */ + + static inline int __attribute__ ((unused)) +-elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) ++elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], ++ int lazy, int profile) + { + extern void _dl_runtime_resolve (Elf64_Word); + extern void _dl_runtime_profile (Elf64_Word); +@@ -270,8 +271,9 @@ elf_machine_plt_value (struct link_map *map, const Elf64_Rela *reloc, + + auto inline void + __attribute__ ((always_inline)) +-elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, +- const Elf64_Sym *sym, const struct r_found_version *version, ++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], ++ const Elf64_Rela *reloc, const Elf64_Sym *sym, ++ const struct r_found_version *version, + void *const reloc_addr_arg, int skip_ifunc) + { + Elf64_Addr *const reloc_addr = reloc_addr_arg; +@@ -304,7 +306,8 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc, + /* Only needed for R_390_COPY below. */ + const Elf64_Sym *const refsym = sym; + #endif +- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); ++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, ++ r_type); + Elf64_Addr value = SYMBOL_ADDRESS (sym_map, sym, true); + + if (sym != NULL +@@ -449,7 +452,7 @@ elf_machine_rela_relative (Elf64_Addr l_addr, const Elf64_Rela *reloc, + + auto inline void + __attribute__ ((always_inline)) +-elf_machine_lazy_rel (struct link_map *map, ++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], + Elf64_Addr l_addr, const Elf64_Rela *reloc, + int skip_ifunc) + { +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index b94d3b39ec1dca64..5262aa69c06aa8db 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -62,7 +62,8 @@ elf_machine_load_address (void) + entries will jump to the on-demand fixup code in dl-runtime.c. */ + + static inline int __attribute__ ((unused, always_inline)) +-elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) ++elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], ++ int lazy, int profile) + { + Elf64_Addr *got; + extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden; +@@ -260,8 +261,9 @@ elf_machine_plt_value (struct link_map *map, const ElfW(Rela) *reloc, + + auto inline void + __attribute__ ((always_inline)) +-elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, +- const ElfW(Sym) *sym, const struct r_found_version *version, ++elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[], ++ const ElfW(Rela) *reloc, const ElfW(Sym) *sym, ++ const struct r_found_version *version, + void *const reloc_addr_arg, int skip_ifunc) + { + ElfW(Addr) *const reloc_addr = reloc_addr_arg; +@@ -300,7 +302,7 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, + # ifndef RTLD_BOOTSTRAP + const ElfW(Sym) *const refsym = sym; + # endif +- struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); ++ struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version, r_type); + ElfW(Addr) value = SYMBOL_ADDRESS (sym_map, sym, true); + + if (sym != NULL +@@ -539,7 +541,7 @@ elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc, + + auto inline void + __attribute ((always_inline)) +-elf_machine_lazy_rel (struct link_map *map, ++elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], + ElfW(Addr) l_addr, const ElfW(Rela) *reloc, + int skip_ifunc) + { +@@ -573,7 +575,7 @@ elf_machine_lazy_rel (struct link_map *map, + + /* Always initialize TLS descriptors completely at load time, in + case static TLS is allocated for it that requires locking. */ +- elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc); ++ elf_machine_rela (map, scope, reloc, sym, version, reloc_addr, skip_ifunc); + } + else if (__glibc_unlikely (r_type == R_X86_64_IRELATIVE)) + { diff --git a/SOURCES/glibc-rh2047981-13.patch b/SOURCES/glibc-rh2047981-13.patch new file mode 100644 index 0000000..d67e40f --- /dev/null +++ b/SOURCES/glibc-rh2047981-13.patch @@ -0,0 +1,65 @@ +commit 54816ae98d57930b7c945f17485714a5574bfe47 +Author: Adhemerval Zanella +Date: Thu Jul 29 11:13:57 2021 -0300 + + elf: Move LAV_CURRENT to link_lavcurrent.h + + No functional change. + +diff --git a/bits/link_lavcurrent.h b/bits/link_lavcurrent.h +new file mode 100644 +index 0000000000000000..44fbea1e8060997f +--- /dev/null ++++ b/bits/link_lavcurrent.h +@@ -0,0 +1,25 @@ ++/* Data structure for communication from the run-time dynamic linker for ++ loaded ELF shared objects. LAV_CURRENT definition. ++ 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 ++ . */ ++ ++#ifndef _LINK_H ++# error "Never include directly; use instead." ++#endif ++ ++/* Version numbers for la_version handshake interface. */ ++#define LAV_CURRENT 1 +diff --git a/elf/Makefile b/elf/Makefile +index 6262a4a65cfd2148..b9751e8bd87c4f71 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -21,7 +21,7 @@ subdir := elf + + include ../Makeconfig + +-headers = elf.h bits/elfclass.h link.h bits/link.h ++headers = elf.h bits/elfclass.h link.h bits/link.h bits/link_lavcurrent.h + routines = $(all-dl-routines) dl-support dl-iteratephdr \ + dl-addr dl-addr-obj enbl-secure dl-profstub \ + dl-origin dl-libc dl-sym dl-sysdep dl-error \ +diff --git a/elf/link.h b/elf/link.h +index c67a50dd8ee9187e..cbda60b4135997f6 100644 +--- a/elf/link.h ++++ b/elf/link.h +@@ -96,7 +96,7 @@ struct link_map + #ifdef __USE_GNU + + /* Version numbers for la_version handshake interface. */ +-#define LAV_CURRENT 1 ++#include + + /* Activity types signaled through la_activity. */ + enum diff --git a/SOURCES/glibc-rh2047981-14.patch b/SOURCES/glibc-rh2047981-14.patch new file mode 100644 index 0000000..1d1295c --- /dev/null +++ b/SOURCES/glibc-rh2047981-14.patch @@ -0,0 +1,388 @@ +Added $(objpfx)tst-audit18: $(libdl) in elf/Makefile since +we still have $(libdl) in RHEL8. + +commit ed3ce71f5c64c5f07cbde0ef03554ea8950d8f2c +Author: Adhemerval Zanella +Date: Thu Nov 11 09:28:21 2021 -0300 + + elf: Move la_activity (LA_ACT_ADD) after _dl_add_to_namespace_list() (BZ #28062) + + It ensures that the the namespace is guaranteed to not be empty. + + Checked on x86_64-linux-gnu. + + Reviewed-by: Florian Weimer + +Conflicts: + elf/Makefile + elf/dl-load.c + Conflict with missing MAP_ANON removal. + +diff --git a/elf/Makefile b/elf/Makefile +index b9751e8bd87c4f71..2312184692433313 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -219,6 +219,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-dlmopen-dlerror \ + tst-dlmopen-gethostbyname \ + tst-audit17 \ ++ tst-audit18 \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -354,6 +355,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \ + tst-dlmopen-dlerror-mod \ + tst-dlmopen-gethostbyname-mod \ ++ tst-auditmod18 \ ++ tst-audit18mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1539,6 +1542,11 @@ $(objpfx)tst-auditmod17.so: $(objpfx)tst-auditmod17.os + CFLAGS-.os += $(call elide-stack-protector,.os,tst-auditmod17) + tst-audit17-ENV = LD_AUDIT=$(objpfx)tst-auditmod17.so + ++$(objpfx)tst-audit18: $(libdl) ++$(objpfx)tst-audit18.out: $(objpfx)tst-auditmod18.so \ ++ $(objpfx)tst-audit18mod.so ++tst-audit18-ARGS = -- $(host-test-program-cmd) ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 303e6594f9af9b7e..de5aef5777045da5 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -978,42 +978,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + } + #endif + +- /* Signal that we are going to add new objects. */ +- if (r->r_state == RT_CONSISTENT) +- { +-#ifdef SHARED +- /* Auditing checkpoint: we are going to add new objects. */ +- if ((mode & __RTLD_AUDIT) == 0 +- && __glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- struct link_map *head = GL(dl_ns)[nsid]._ns_loaded; +- /* Do not call the functions for any auditing object. */ +- if (head->l_auditing == 0) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->activity != NULL) +- afct->activity (&link_map_audit_state (head, cnt)->cookie, +- LA_ACT_ADD); +- +- afct = afct->next; +- } +- } +- } +-#endif +- +- /* Notify the debugger we have added some objects. We need to +- call _dl_debug_initialize in a static program in case dynamic +- linking has not been used before. */ +- r->r_state = RT_ADD; +- _dl_debug_state (); +- LIBC_PROBE (map_start, 2, nsid, r); +- make_consistent = true; +- } +- else +- assert (r->r_state == RT_ADD); +- + /* Enter the new object in the list of loaded objects. */ + l = _dl_new_object (realname, name, l_type, loader, mode, nsid); + if (__glibc_unlikely (l == NULL)) +@@ -1432,6 +1396,44 @@ cannot enable executable stack as shared object requires"); + /* Now that the object is fully initialized add it to the object list. */ + _dl_add_to_namespace_list (l, nsid); + ++ /* Signal that we are going to add new objects. */ ++ if (r->r_state == RT_CONSISTENT) ++ { ++#ifdef SHARED ++ /* Auditing checkpoint: we are going to add new objects. Since this ++ is called after _dl_add_to_namespace_list the namespace is guaranteed ++ to not be empty. */ ++ if ((mode & __RTLD_AUDIT) == 0 ++ && __glibc_unlikely (GLRO(dl_naudit) > 0)) ++ { ++ struct link_map *head = GL(dl_ns)[nsid]._ns_loaded; ++ /* Do not call the functions for any auditing object. */ ++ if (head->l_auditing == 0) ++ { ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->activity != NULL) ++ afct->activity (&link_map_audit_state (head, cnt)->cookie, ++ LA_ACT_ADD); ++ ++ afct = afct->next; ++ } ++ } ++ } ++#endif ++ ++ /* Notify the debugger we have added some objects. We need to ++ call _dl_debug_initialize in a static program in case dynamic ++ linking has not been used before. */ ++ r->r_state = RT_ADD; ++ _dl_debug_state (); ++ LIBC_PROBE (map_start, 2, nsid, r); ++ make_consistent = true; ++ } ++ else ++ assert (r->r_state == RT_ADD); ++ + #ifdef SHARED + /* Auditing checkpoint: we have a new object. */ + if (__glibc_unlikely (GLRO(dl_naudit) > 0) +diff --git a/elf/tst-audit18.c b/elf/tst-audit18.c +new file mode 100644 +index 0000000000000000..ef784908f60d50aa +--- /dev/null ++++ b/elf/tst-audit18.c +@@ -0,0 +1,129 @@ ++/* Check DT_AUDIT with dlmopen. ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++static int ++handle_restart (void) ++{ ++ { ++ void *h = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); ++ ++ pid_t (*s) (void) = xdlsym (h, "getpid"); ++ TEST_COMPARE (s (), getpid ()); ++ ++ xdlclose (h); ++ } ++ ++ { ++ void *h = xdlmopen (LM_ID_NEWLM, "tst-audit18mod.so", RTLD_NOW); ++ ++ int (*foo) (void) = xdlsym (h, "foo"); ++ TEST_COMPARE (foo (), 10); ++ ++ xdlclose (h); ++ } ++ ++ return 0; ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ - One our fource parameters left if called initially: ++ + path to ld.so optional ++ + "--library-path" optional ++ + the library path optional ++ + the application name */ ++ ++ if (restart) ++ return handle_restart (); ++ ++ char *spargv[9]; ++ int i = 0; ++ for (; i < argc - 1; i++) ++ spargv[i] = argv[i + 1]; ++ spargv[i++] = (char *) "--direct"; ++ spargv[i++] = (char *) "--restart"; ++ spargv[i] = NULL; ++ ++ setenv ("LD_AUDIT", "tst-auditmod18.so", 0); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit18", 0, sc_allow_stderr); ++ ++ struct ++ { ++ const char *name; ++ bool found; ++ } audit_iface[] = ++ { ++ { "la_version", false }, ++ { "la_objsearch", false }, ++ { "la_activity", false }, ++ { "la_objopen", false }, ++ { "la_objclose", false }, ++ { "la_preinit", false }, ++#if __WORDSIZE == 32 ++ { "la_symbind32", false }, ++#elif __WORDSIZE == 64 ++ { "la_symbind64", false }, ++#endif ++ }; ++ ++ /* Some hooks are called more than once but the test only check if any ++ is called at least once. */ ++ FILE *out = fmemopen (result.err.buffer, result.err.length, "r"); ++ TEST_VERIFY (out != NULL); ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ while (xgetline (&buffer, &buffer_length, out)) ++ { ++ for (int i = 0; i < array_length (audit_iface); i++) ++ if (strncmp (buffer, audit_iface[i].name, ++ strlen (audit_iface[i].name)) == 0) ++ audit_iface[i].found = true; ++ } ++ free (buffer); ++ xfclose (out); ++ ++ for (int i = 0; i < array_length (audit_iface); i++) ++ TEST_COMPARE (audit_iface[i].found, true); ++ ++ support_capture_subprocess_free (&result); ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-audit18mod.c b/elf/tst-audit18mod.c +new file mode 100644 +index 0000000000000000..096a9167c9f8353f +--- /dev/null ++++ b/elf/tst-audit18mod.c +@@ -0,0 +1,23 @@ ++/* Check DT_AUDIT with dlmopen. ++ 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 ++ . */ ++ ++int ++foo (void) ++{ ++ return 10; ++} +diff --git a/elf/tst-auditmod18.c b/elf/tst-auditmod18.c +new file mode 100644 +index 0000000000000000..182992e9fdb1620c +--- /dev/null ++++ b/elf/tst-auditmod18.c +@@ -0,0 +1,73 @@ ++/* Check DT_AUDIT with dlmopen. ++ 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 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ fprintf (stderr, "%s\n", __func__); ++ return LAV_CURRENT; ++} ++ ++char * ++la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag) ++{ ++ fprintf (stderr, "%s\n", __func__); ++ return (char *) name; ++} ++ ++void ++la_activity (uintptr_t *cookie, unsigned int flag) ++{ ++ fprintf (stderr, "%s\n", __func__); ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ fprintf (stderr, "%s\n", __func__); ++ return LA_FLG_BINDTO | LA_FLG_BINDFROM; ++} ++ ++unsigned int ++la_objclose (uintptr_t *cookie) ++{ ++ fprintf (stderr, "%s\n", __func__); ++ return 0; ++} ++ ++void ++la_preinit (uintptr_t *cookie) ++{ ++ fprintf (stderr, "%s\n", __func__); ++} ++ ++uintptr_t ++#if __ELF_NATIVE_CLASS == 32 ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, unsigned int *flags, const char *symname) ++#else ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, unsigned int *flags, const char *symname) ++#endif ++{ ++ fprintf (stderr, "%s\n", __func__); ++ return sym->st_value; ++} diff --git a/SOURCES/glibc-rh2047981-15.patch b/SOURCES/glibc-rh2047981-15.patch new file mode 100644 index 0000000..7da5392 --- /dev/null +++ b/SOURCES/glibc-rh2047981-15.patch @@ -0,0 +1,160 @@ +commit aee6e90f93e285016b6cd9c8bd00402c19ba271b +Author: Adhemerval Zanella +Date: Mon Jul 19 15:47:51 2021 -0300 + + elf: Add _dl_audit_objopen + + It consolidates the code required to call la_objopen audit callback. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index 2312184692433313..08a32a712a34f2cc 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -64,7 +64,8 @@ elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ + # interpreter and operating independent of libc. + rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \ + dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \ +- dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu ++ dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu \ ++ dl-audit + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +new file mode 100644 +index 0000000000000000..4066dfe85146b9d4 +--- /dev/null ++++ b/elf/dl-audit.c +@@ -0,0 +1,39 @@ ++/* Audit common functions. ++ 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 ++ ++void ++_dl_audit_objopen (struct link_map *l, Lmid_t nsid) ++{ ++ if (__glibc_likely (GLRO(dl_naudit) == 0)) ++ return; ++ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->objopen != NULL) ++ { ++ struct auditstate *state = link_map_audit_state (l, cnt); ++ state->bindflags = afct->objopen (l, nsid, &state->cookie); ++ l->l_audit_any_plt |= state->bindflags != 0; ++ } ++ ++ afct = afct->next; ++ } ++} +diff --git a/elf/dl-load.c b/elf/dl-load.c +index de5aef5777045da5..c11b1d1781e9b40b 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1436,22 +1436,8 @@ cannot enable executable stack as shared object requires"); + + #ifdef SHARED + /* Auditing checkpoint: we have a new object. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0) +- && !GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->objopen != NULL) +- { +- struct auditstate *state = link_map_audit_state (l, cnt); +- state->bindflags = afct->objopen (l, nsid, &state->cookie); +- l->l_audit_any_plt |= state->bindflags != 0; +- } +- +- afct = afct->next; +- } +- } ++ if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing) ++ _dl_audit_objopen (l, nsid); + #endif + + return l; +diff --git a/elf/rtld.c b/elf/rtld.c +index f3836b8a78faaf27..1982e42390760e0a 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1075,25 +1075,6 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); + dlmargs.map->l_auditing = 1; + } + +-/* Notify the the audit modules that the object MAP has already been +- loaded. */ +-static void +-notify_audit_modules_of_loaded_object (struct link_map *map) +-{ +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->objopen != NULL) +- { +- struct auditstate *state = link_map_audit_state (map, cnt); +- state->bindflags = afct->objopen (map, LM_ID_BASE, &state->cookie); +- map->l_audit_any_plt |= state->bindflags != 0; +- } +- +- afct = afct->next; +- } +-} +- + /* Load all audit modules. */ + static void + load_audit_modules (struct link_map *main_map, struct audit_list *audit_list) +@@ -1112,8 +1093,8 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list) + program and the dynamic linker itself). */ + if (GLRO(dl_naudit) > 0) + { +- notify_audit_modules_of_loaded_object (main_map); +- notify_audit_modules_of_loaded_object (&GL(dl_rtld_map)); ++ _dl_audit_objopen (main_map, LM_ID_BASE); ++ _dl_audit_objopen (&GL(dl_rtld_map), LM_ID_BASE); + } + } + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 2dd6f0c3c4aaaef5..410f070e28b74bdf 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1268,6 +1268,11 @@ link_map_audit_state (struct link_map *l, size_t index) + { + return &l->l_audit[index]; + } ++ ++/* Call the la_objopen from the audit modules for the link_map L on the ++ namespace identification NSID. */ ++void _dl_audit_objopen (struct link_map *l, Lmid_t nsid) ++ attribute_hidden; + #endif /* SHARED */ + + __END_DECLS diff --git a/SOURCES/glibc-rh2047981-16.patch b/SOURCES/glibc-rh2047981-16.patch new file mode 100644 index 0000000..eec1516 --- /dev/null +++ b/SOURCES/glibc-rh2047981-16.patch @@ -0,0 +1,253 @@ +commit 3dac3959a5cb585b065cef2cb8a8d909c907e202 +Author: Adhemerval Zanella +Date: Tue Jul 20 11:03:34 2021 -0300 + + elf: Add _dl_audit_activity_map and _dl_audit_activity_nsid + + It consolidates the code required to call la_activity audit + callback. + + Also for a new Lmid_t the namespace link_map list are empty, so it + requires to check if before using it. This can happen for when audit + module is used along with dlmopen. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index 4066dfe85146b9d4..74b87f4b39be75e1 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -18,6 +18,32 @@ + + #include + ++void ++_dl_audit_activity_map (struct link_map *l, int action) ++{ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->activity != NULL) ++ afct->activity (&link_map_audit_state (l, cnt)->cookie, action); ++ afct = afct->next; ++ } ++} ++ ++void ++_dl_audit_activity_nsid (Lmid_t nsid, int action) ++{ ++ /* If head is NULL, the namespace has become empty, and the audit interface ++ does not give us a way to signal LA_ACT_CONSISTENT for it because the ++ first loaded module is used to identify the namespace. */ ++ struct link_map *head = GL(dl_ns)[nsid]._ns_loaded; ++ if (__glibc_likely (GLRO(dl_naudit) == 0) ++ || head == NULL || head->l_auditing) ++ return; ++ ++ _dl_audit_activity_map (head, action); ++} ++ + void + _dl_audit_objopen (struct link_map *l, Lmid_t nsid) + { +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 698bda929c0eab6c..1ba594b600c4c87a 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -478,25 +478,7 @@ _dl_close_worker (struct link_map *map, bool force) + + #ifdef SHARED + /* Auditing checkpoint: we will start deleting objects. */ +- if (__glibc_unlikely (do_audit)) +- { +- struct link_map *head = ns->_ns_loaded; +- struct audit_ifaces *afct = GLRO(dl_audit); +- /* Do not call the functions for any auditing object. */ +- if (head->l_auditing == 0) +- { +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->activity != NULL) +- { +- struct auditstate *state = link_map_audit_state (head, cnt); +- afct->activity (&state->cookie, LA_ACT_DELETE); +- } +- +- afct = afct->next; +- } +- } +- } ++ _dl_audit_activity_nsid (nsid, LA_ACT_DELETE); + #endif + + /* Notify the debugger we are about to remove some loaded objects. */ +@@ -791,32 +773,9 @@ _dl_close_worker (struct link_map *map, bool force) + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + #ifdef SHARED +- /* Auditing checkpoint: we have deleted all objects. */ +- if (__glibc_unlikely (do_audit)) +- { +- struct link_map *head = ns->_ns_loaded; +- /* If head is NULL, the namespace has become empty, and the +- audit interface does not give us a way to signal +- LA_ACT_CONSISTENT for it because the first loaded module is +- used to identify the namespace. +- +- Furthermore, do not notify auditors of the cleanup of a +- failed audit module loading attempt. */ +- if (head != NULL && head->l_auditing == 0) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->activity != NULL) +- { +- struct auditstate *state = link_map_audit_state (head, cnt); +- afct->activity (&state->cookie, LA_ACT_CONSISTENT); +- } +- +- afct = afct->next; +- } +- } +- } ++ /* Auditing checkpoint: we have deleted all objects. Also, do not notify ++ auditors of the cleanup of a failed audit module loading attempt. */ ++ _dl_audit_activity_nsid (nsid, LA_ACT_CONSISTENT); + #endif + + if (__builtin_expect (ns->_ns_loaded == NULL, 0) +diff --git a/elf/dl-load.c b/elf/dl-load.c +index c11b1d1781e9b40b..8a18c761bb753e37 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1403,24 +1403,8 @@ cannot enable executable stack as shared object requires"); + /* Auditing checkpoint: we are going to add new objects. Since this + is called after _dl_add_to_namespace_list the namespace is guaranteed + to not be empty. */ +- if ((mode & __RTLD_AUDIT) == 0 +- && __glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- struct link_map *head = GL(dl_ns)[nsid]._ns_loaded; +- /* Do not call the functions for any auditing object. */ +- if (head->l_auditing == 0) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->activity != NULL) +- afct->activity (&link_map_audit_state (head, cnt)->cookie, +- LA_ACT_ADD); +- +- afct = afct->next; +- } +- } +- } ++ if ((mode & __RTLD_AUDIT) == 0) ++ _dl_audit_activity_nsid (nsid, LA_ACT_ADD); + #endif + + /* Notify the debugger we have added some objects. We need to +diff --git a/elf/dl-open.c b/elf/dl-open.c +index b5a4da04907d8d29..660a56b2fb2639cd 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -598,25 +598,7 @@ dl_open_worker_begin (void *a) + + #ifdef SHARED + /* Auditing checkpoint: we have added all objects. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- struct link_map *head = GL(dl_ns)[new->l_ns]._ns_loaded; +- /* Do not call the functions for any auditing object. */ +- if (head->l_auditing == 0) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->activity != NULL) +- { +- struct auditstate *state = link_map_audit_state (head, cnt); +- afct->activity (&state->cookie, LA_ACT_CONSISTENT); +- } +- +- afct = afct->next; +- } +- } +- } ++ _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT); + #endif + + /* Notify the debugger all new objects are now ready to go. */ +diff --git a/elf/rtld.c b/elf/rtld.c +index 1982e42390760e0a..767acd122262b824 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1799,18 +1799,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + /* Auditing checkpoint: we are ready to signal that the initial map + is being constructed. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->activity != NULL) +- afct->activity (&link_map_audit_state (main_map, cnt)->cookie, +- LA_ACT_ADD); +- +- afct = afct->next; +- } +- } ++ _dl_audit_activity_map (main_map, LA_ACT_ADD); + + /* We have two ways to specify objects to preload: via environment + variable and via the file /etc/ld.so.preload. The latter can also +@@ -2484,23 +2473,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + #ifdef SHARED + /* Auditing checkpoint: we have added all objects. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded; +- /* Do not call the functions for any auditing object. */ +- if (head->l_auditing == 0) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->activity != NULL) +- afct->activity (&link_map_audit_state (head, cnt)->cookie, +- LA_ACT_CONSISTENT); +- +- afct = afct->next; +- } +- } +- } ++ _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT); + #endif + + /* Notify the debugger all new objects are now ready to go. We must re-get +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 410f070e28b74bdf..05737342d6287233 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1269,6 +1269,16 @@ link_map_audit_state (struct link_map *l, size_t index) + return &l->l_audit[index]; + } + ++/* Call the la_activity from the audit modules from the link map L and issues ++ the ACTION argument. */ ++void _dl_audit_activity_map (struct link_map *l, int action) ++ attribute_hidden; ++ ++/* Call the la_activity from the audit modules from the link map from the ++ namespace NSID and issues the ACTION argument. */ ++void _dl_audit_activity_nsid (Lmid_t nsid, int action) ++ attribute_hidden; ++ + /* Call the la_objopen from the audit modules for the link_map L on the + namespace identification NSID. */ + void _dl_audit_objopen (struct link_map *l, Lmid_t nsid) diff --git a/SOURCES/glibc-rh2047981-17.patch b/SOURCES/glibc-rh2047981-17.patch new file mode 100644 index 0000000..4a22e82 --- /dev/null +++ b/SOURCES/glibc-rh2047981-17.patch @@ -0,0 +1,156 @@ +commit c91008d3490e4e3ce29520068405f081f0d368ca +Author: Adhemerval Zanella +Date: Tue Jul 20 13:47:36 2021 -0300 + + elf: Add _dl_audit_objsearch + + It consolidates the code required to call la_objsearch audit + callback. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index 74b87f4b39be75e1..5682427220569d90 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -44,6 +44,28 @@ _dl_audit_activity_nsid (Lmid_t nsid, int action) + _dl_audit_activity_map (head, action); + } + ++const char * ++_dl_audit_objsearch (const char *name, struct link_map *l, unsigned int code) ++{ ++ if (l == NULL || l->l_auditing || code == 0) ++ return name; ++ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->objsearch != NULL) ++ { ++ struct auditstate *state = link_map_audit_state (l, cnt); ++ name = afct->objsearch (name, &state->cookie, code); ++ if (name == NULL) ++ return NULL; ++ } ++ afct = afct->next; ++ } ++ ++ return name; ++} ++ + void + _dl_audit_objopen (struct link_map *l, Lmid_t nsid) + { +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 8a18c761bb753e37..1613217a236c7fc3 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1517,32 +1517,20 @@ open_verify (const char *name, int fd, + + #ifdef SHARED + /* Give the auditing libraries a chance. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0) && whatcode != 0 +- && loader->l_auditing == 0) ++ if (__glibc_unlikely (GLRO(dl_naudit) > 0)) + { + const char *original_name = name; +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->objsearch != NULL) +- { +- struct auditstate *state = link_map_audit_state (loader, cnt); +- name = afct->objsearch (name, &state->cookie, whatcode); +- if (name == NULL) +- /* Ignore the path. */ +- return -1; +- } +- +- afct = afct->next; +- } ++ name = _dl_audit_objsearch (name, loader, whatcode); ++ if (name == NULL) ++ return -1; + + if (fd != -1 && name != original_name && strcmp (name, original_name)) +- { +- /* An audit library changed what we're supposed to open, +- so FD no longer matches it. */ +- __close_nocancel (fd); +- fd = -1; +- } ++ { ++ /* An audit library changed what we're supposed to open, ++ so FD no longer matches it. */ ++ __close_nocancel (fd); ++ fd = -1; ++ } + } + #endif + +@@ -1992,36 +1980,17 @@ _dl_map_object (struct link_map *loader, const char *name, + #ifdef SHARED + /* Give the auditing libraries a chance to change the name before we + try anything. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0) +- && (loader == NULL || loader->l_auditing == 0)) ++ if (__glibc_unlikely (GLRO(dl_naudit) > 0)) + { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ const char *before = name; ++ name = _dl_audit_objsearch (name, loader, LA_SER_ORIG); ++ if (name == NULL) + { +- if (afct->objsearch != NULL) +- { +- const char *before = name; +- struct auditstate *state = link_map_audit_state (loader, cnt); +- name = afct->objsearch (name, &state->cookie, LA_SER_ORIG); +- if (name == NULL) +- { +- /* Do not try anything further. */ +- fd = -1; +- goto no_file; +- } +- if (before != name && strcmp (before, name) != 0) +- { +- if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) +- _dl_debug_printf ("audit changed filename %s -> %s\n", +- before, name); +- +- if (origname == NULL) +- origname = before; +- } +- } +- +- afct = afct->next; ++ fd = -1; ++ goto no_file; + } ++ if (before != name && strcmp (before, name) != 0) ++ origname = before; + } + #endif + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 05737342d6287233..da83e717e8cd8e0b 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1269,6 +1269,13 @@ link_map_audit_state (struct link_map *l, size_t index) + return &l->l_audit[index]; + } + ++/* Call the la_objsearch from the audit modules from the link map L. If ++ ORIGNAME is non NULL, it is updated with the revious name prior calling ++ la_objsearch. */ ++const char *_dl_audit_objsearch (const char *name, struct link_map *l, ++ unsigned int code) ++ attribute_hidden; ++ + /* Call the la_activity from the audit modules from the link map L and issues + the ACTION argument. */ + void _dl_audit_activity_map (struct link_map *l, int action) diff --git a/SOURCES/glibc-rh2047981-18.patch b/SOURCES/glibc-rh2047981-18.patch new file mode 100644 index 0000000..b866295 --- /dev/null +++ b/SOURCES/glibc-rh2047981-18.patch @@ -0,0 +1,122 @@ +commit 311c9ee54ea963ff69bd3a2e6981c37e893b4c3e +Author: Adhemerval Zanella +Date: Tue Jul 20 14:04:51 2021 -0300 + + elf: Add _dl_audit_objclose + + It consolidates the code required to call la_objclose audit + callback. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index 5682427220569d90..cb1c3de93cba447b 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -85,3 +85,24 @@ _dl_audit_objopen (struct link_map *l, Lmid_t nsid) + afct = afct->next; + } + } ++ ++void ++_dl_audit_objclose (struct link_map *l) ++{ ++ if (__glibc_likely (GLRO(dl_naudit) == 0) ++ || GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing) ++ return; ++ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->objclose != NULL) ++ { ++ struct auditstate *state= link_map_audit_state (l, cnt); ++ /* Return value is ignored. */ ++ afct->objclose (&state->cookie); ++ } ++ ++ afct = afct->next; ++ } ++} +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 1ba594b600c4c87a..74ca9a85dd309780 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -266,9 +266,6 @@ _dl_close_worker (struct link_map *map, bool force) + used + (nsid == LM_ID_BASE), true); + + /* Call all termination functions at once. */ +-#ifdef SHARED +- bool do_audit = GLRO(dl_naudit) > 0 && !ns->_ns_loaded->l_auditing; +-#endif + bool unload_any = false; + bool scope_mem_left = false; + unsigned int unload_global = 0; +@@ -302,22 +299,7 @@ _dl_close_worker (struct link_map *map, bool force) + + #ifdef SHARED + /* Auditing checkpoint: we remove an object. */ +- if (__glibc_unlikely (do_audit)) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->objclose != NULL) +- { +- struct auditstate *state +- = link_map_audit_state (imap, cnt); +- /* Return value is ignored. */ +- (void) afct->objclose (&state->cookie); +- } +- +- afct = afct->next; +- } +- } ++ _dl_audit_objclose (imap); + #endif + + /* This object must not be used anymore. */ +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index 915ceb104e1c81d6..e102d93647cb8c47 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -146,21 +146,7 @@ _dl_fini (void) + + #ifdef SHARED + /* Auditing checkpoint: another object closed. */ +- if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0)) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->objclose != NULL) +- { +- struct auditstate *state +- = link_map_audit_state (l, cnt); +- /* Return value is ignored. */ +- (void) afct->objclose (&state->cookie); +- } +- afct = afct->next; +- } +- } ++ _dl_audit_objclose (l); + #endif + } + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index da83e717e8cd8e0b..3db25c5be1acf871 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1290,6 +1290,10 @@ void _dl_audit_activity_nsid (Lmid_t nsid, int action) + namespace identification NSID. */ + void _dl_audit_objopen (struct link_map *l, Lmid_t nsid) + attribute_hidden; ++ ++/* Call the la_objclose from the audit modules for the link_map L. */ ++void _dl_audit_objclose (struct link_map *l) ++ attribute_hidden; + #endif /* SHARED */ + + __END_DECLS diff --git a/SOURCES/glibc-rh2047981-19.patch b/SOURCES/glibc-rh2047981-19.patch new file mode 100644 index 0000000..2c55405 --- /dev/null +++ b/SOURCES/glibc-rh2047981-19.patch @@ -0,0 +1,333 @@ +commit cda4f265c65fb6c4ce38ca1cf0a7e527c5e77cd5 +Author: Adhemerval Zanella +Date: Tue Jul 20 15:58:35 2021 -0300 + + elf: Add _dl_audit_symbind_alt and _dl_audit_symbind + + It consolidates the code required to call la_symbind{32,64} audit + callback. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +diff --git a/elf/Versions b/elf/Versions +index be88c48e6d45a937..c5d4342cf1f5124c 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -59,6 +59,7 @@ ld { + _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info; + _dl_deallocate_tls; _dl_make_stack_executable; + _dl_rtld_di_serinfo; _dl_starting_up; _dl_fatal_printf; ++ _dl_audit_symbind_alt; + _rtld_global; _rtld_global_ro; + + # Only here for gdb while a better method is developed. +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index cb1c3de93cba447b..a21530f30bc5524b 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + + void +@@ -106,3 +107,124 @@ _dl_audit_objclose (struct link_map *l) + afct = afct->next; + } + } ++ ++void ++_dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref, void **value, ++ lookup_t result) ++{ ++ if ((l->l_audit_any_plt | result->l_audit_any_plt) == 0) ++ return; ++ ++ const char *strtab = (const char *) D_PTR (result, l_info[DT_STRTAB]); ++ /* Compute index of the symbol entry in the symbol table of the DSO with ++ the definition. */ ++ unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, l_info[DT_SYMTAB])); ++ ++ unsigned int altvalue = 0; ++ /* Synthesize a symbol record where the st_value field is the result. */ ++ ElfW(Sym) sym = *ref; ++ sym.st_value = (ElfW(Addr)) *value; ++ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ struct auditstate *match_audit = link_map_audit_state (l, cnt); ++ struct auditstate *result_audit = link_map_audit_state (result, cnt); ++ if (afct->symbind != NULL ++ && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0 ++ || ((result_audit->bindflags & LA_FLG_BINDTO) ++ != 0))) ++ { ++ unsigned int flags = altvalue | LA_SYMB_DLSYM; ++ uintptr_t new_value = afct->symbind (&sym, ndx, ++ &match_audit->cookie, ++ &result_audit->cookie, ++ &flags, strtab + ref->st_name); ++ if (new_value != (uintptr_t) sym.st_value) ++ { ++ altvalue = LA_SYMB_ALTVALUE; ++ sym.st_value = new_value; ++ } ++ ++ afct = afct->next; ++ } ++ ++ *value = (void *) sym.st_value; ++ } ++} ++rtld_hidden_def (_dl_audit_symbind_alt) ++ ++void ++_dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, ++ const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value, ++ lookup_t result) ++{ ++ reloc_result->bound = result; ++ /* Compute index of the symbol entry in the symbol table of the DSO with the ++ definition. */ ++ reloc_result->boundndx = (defsym - (ElfW(Sym) *) D_PTR (result, ++ l_info[DT_SYMTAB])); ++ ++ if ((l->l_audit_any_plt | result->l_audit_any_plt) == 0) ++ { ++ /* Set all bits since this symbol binding is not interesting. */ ++ reloc_result->enterexit = (1u << DL_NNS) - 1; ++ return; ++ } ++ ++ /* Synthesize a symbol record where the st_value field is the result. */ ++ ElfW(Sym) sym = *defsym; ++ sym.st_value = DL_FIXUP_VALUE_ADDR (*value); ++ ++ /* Keep track whether there is any interest in tracing the call in the lower ++ two bits. */ ++ assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8); ++ assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3); ++ reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT; ++ ++ const char *strtab2 = (const void *) D_PTR (result, l_info[DT_STRTAB]); ++ ++ unsigned int flags = 0; ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ /* XXX Check whether both DSOs must request action or only one */ ++ struct auditstate *l_state = link_map_audit_state (l, cnt); ++ struct auditstate *result_state = link_map_audit_state (result, cnt); ++ if ((l_state->bindflags & LA_FLG_BINDFROM) != 0 ++ && (result_state->bindflags & LA_FLG_BINDTO) != 0) ++ { ++ if (afct->symbind != NULL) ++ { ++ uintptr_t new_value = afct->symbind (&sym, ++ reloc_result->boundndx, ++ &l_state->cookie, ++ &result_state->cookie, ++ &flags, ++ strtab2 + defsym->st_name); ++ if (new_value != (uintptr_t) sym.st_value) ++ { ++ flags |= LA_SYMB_ALTVALUE; ++ sym.st_value = new_value; ++ } ++ } ++ ++ /* Remember the results for every audit library and store a summary ++ in the first two bits. */ ++ reloc_result->enterexit &= flags & (LA_SYMB_NOPLTENTER ++ | LA_SYMB_NOPLTEXIT); ++ reloc_result->enterexit |= ((flags & (LA_SYMB_NOPLTENTER ++ | LA_SYMB_NOPLTEXIT)) ++ << ((cnt + 1) * 2)); ++ } ++ else ++ /* If the bind flags say this auditor is not interested, set the bits ++ manually. */ ++ reloc_result->enterexit |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ++ << ((cnt + 1) * 2)); ++ afct = afct->next; ++ } ++ ++ reloc_result->flags = flags; ++ *value = DL_FIXUP_ADDR_VALUE (sym.st_value); ++} +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index 4ccd7c30678fafad..d4840a7c17441126 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -296,84 +296,7 @@ _dl_profile_fixup ( + auditing libraries the possibility to change the value and + tell us whether further auditing is wanted. */ + if (defsym != NULL && GLRO(dl_naudit) > 0) +- { +- reloc_result->bound = result; +- /* Compute index of the symbol entry in the symbol table of +- the DSO with the definition. */ +- reloc_result->boundndx = (defsym +- - (ElfW(Sym) *) D_PTR (result, +- l_info[DT_SYMTAB])); +- +- /* Determine whether any of the two participating DSOs is +- interested in auditing. */ +- if ((l->l_audit_any_plt | result->l_audit_any_plt) != 0) +- { +- unsigned int flags = 0; +- struct audit_ifaces *afct = GLRO(dl_audit); +- /* Synthesize a symbol record where the st_value field is +- the result. */ +- ElfW(Sym) sym = *defsym; +- sym.st_value = DL_FIXUP_VALUE_ADDR (value); +- +- /* Keep track whether there is any interest in tracing +- the call in the lower two bits. */ +- assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8); +- assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3); +- reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT; +- +- const char *strtab2 = (const void *) D_PTR (result, +- l_info[DT_STRTAB]); +- +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- /* XXX Check whether both DSOs must request action or +- only one */ +- struct auditstate *l_state = link_map_audit_state (l, cnt); +- struct auditstate *result_state +- = link_map_audit_state (result, cnt); +- if ((l_state->bindflags & LA_FLG_BINDFROM) != 0 +- && (result_state->bindflags & LA_FLG_BINDTO) != 0) +- { +- if (afct->symbind != NULL) +- { +- uintptr_t new_value +- = afct->symbind (&sym, reloc_result->boundndx, +- &l_state->cookie, +- &result_state->cookie, +- &flags, +- strtab2 + defsym->st_name); +- if (new_value != (uintptr_t) sym.st_value) +- { +- flags |= LA_SYMB_ALTVALUE; +- sym.st_value = new_value; +- } +- } +- +- /* Remember the results for every audit library and +- store a summary in the first two bits. */ +- reloc_result->enterexit +- &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT); +- reloc_result->enterexit +- |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) +- << ((cnt + 1) * 2)); +- } +- else +- /* If the bind flags say this auditor is not interested, +- set the bits manually. */ +- reloc_result->enterexit +- |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) +- << ((cnt + 1) * 2)); +- +- afct = afct->next; +- } +- +- reloc_result->flags = flags; +- value = DL_FIXUP_ADDR_VALUE (sym.st_value); +- } +- else +- /* Set all bits since this symbol binding is not interesting. */ +- reloc_result->enterexit = (1u << DL_NNS) - 1; +- } ++ _dl_audit_symbind (l, reloc_result, defsym, &value, result); + #endif + + /* Store the result for later runs. */ +diff --git a/elf/dl-sym-post.h b/elf/dl-sym-post.h +index 4c4f574633497789..f33934c92047f293 100644 +--- a/elf/dl-sym-post.h ++++ b/elf/dl-sym-post.h +@@ -52,54 +52,9 @@ _dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value, + tell us whether further auditing is wanted. */ + if (__glibc_unlikely (GLRO(dl_naudit) > 0)) + { +- const char *strtab = (const char *) D_PTR (result, +- l_info[DT_STRTAB]); +- /* Compute index of the symbol entry in the symbol table of +- the DSO with the definition. */ +- unsigned int ndx = (ref - (ElfW(Sym) *) D_PTR (result, +- l_info[DT_SYMTAB])); +- + if (match == NULL) + match = _dl_sym_find_caller_link_map (caller); +- +- if ((match->l_audit_any_plt | result->l_audit_any_plt) != 0) +- { +- unsigned int altvalue = 0; +- struct audit_ifaces *afct = GLRO(dl_audit); +- /* Synthesize a symbol record where the st_value field is +- the result. */ +- ElfW(Sym) sym = *ref; +- sym.st_value = (ElfW(Addr)) value; +- +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- struct auditstate *match_audit +- = link_map_audit_state (match, cnt); +- struct auditstate *result_audit +- = link_map_audit_state (result, cnt); +- if (afct->symbind != NULL +- && ((match_audit->bindflags & LA_FLG_BINDFROM) != 0 +- || ((result_audit->bindflags & LA_FLG_BINDTO) +- != 0))) +- { +- unsigned int flags = altvalue | LA_SYMB_DLSYM; +- uintptr_t new_value +- = afct->symbind (&sym, ndx, +- &match_audit->cookie, +- &result_audit->cookie, +- &flags, strtab + ref->st_name); +- if (new_value != (uintptr_t) sym.st_value) +- { +- altvalue = LA_SYMB_ALTVALUE; +- sym.st_value = new_value; +- } +- } +- +- afct = afct->next; +- } +- +- value = (void *) sym.st_value; +- } ++ _dl_audit_symbind_alt (match, ref, &value, result); + } + #endif + return value; +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 3db25c5be1acf871..fa55c3bde10de52e 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1294,6 +1294,16 @@ void _dl_audit_objopen (struct link_map *l, Lmid_t nsid) + /* Call the la_objclose from the audit modules for the link_map L. */ + void _dl_audit_objclose (struct link_map *l) + attribute_hidden; ++ ++/* Call the la_symbind{32,64} from the audit modules for the link_map L. */ ++void _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, ++ const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value, ++ lookup_t result) ++ attribute_hidden; ++/* Same as _dl_audit_symbind, but also sets LA_SYMB_DLSYM flag. */ ++void _dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref, ++ void **value, lookup_t result); ++rtld_hidden_proto (_dl_audit_symbind_alt) + #endif /* SHARED */ + + __END_DECLS diff --git a/SOURCES/glibc-rh2047981-2.patch b/SOURCES/glibc-rh2047981-2.patch new file mode 100644 index 0000000..02bc403 --- /dev/null +++ b/SOURCES/glibc-rh2047981-2.patch @@ -0,0 +1,70 @@ +commit acdcca72940e060270e4e54d9c0457398110f409 +Author: John David Anglin +Date: Mon Mar 30 21:58:06 2020 +0000 + + Add new file missed in previous hppa commit. + +diff --git a/sysdeps/hppa/dl-runtime.c b/sysdeps/hppa/dl-runtime.c +new file mode 100644 +index 0000000000000000..885a3f1837cbc56d +--- /dev/null ++++ b/sysdeps/hppa/dl-runtime.c +@@ -0,0 +1,58 @@ ++/* On-demand PLT fixup for shared objects. HPPA version. ++ Copyright (C) 2019 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, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++/* Clear PA_GP_RELOC bit in relocation offset. */ ++#define reloc_offset (reloc_arg & ~PA_GP_RELOC) ++#define reloc_index (reloc_arg & ~PA_GP_RELOC) / sizeof (PLTREL) ++ ++#include ++ ++/* The caller has encountered a partially relocated function descriptor. ++ The gp of the descriptor has been updated, but not the ip. We find ++ the function descriptor again and compute the relocation offset and ++ return that to the caller. The caller will continue on to call ++ _dl_fixup with the relocation offset. */ ++ ++ElfW(Word) ++attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE ++_dl_fix_reloc_arg (struct fdesc *fptr, struct link_map *l) ++{ ++ Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type; ++ const Elf32_Rela *reloc; ++ ++ l_addr = l->l_addr; ++ jmprel = D_PTR(l, l_info[DT_JMPREL]); ++ end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val; ++ ++ /* Look for the entry... */ ++ for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela)) ++ { ++ reloc = (const Elf32_Rela *) iplt; ++ r_type = ELF32_R_TYPE (reloc->r_info); ++ ++ if (__builtin_expect (r_type == R_PARISC_IPLT, 1) ++ && fptr == (struct fdesc *) (reloc->r_offset + l_addr)) ++ /* Found entry. Return the reloc offset. */ ++ return iplt - jmprel; ++ } ++ ++ /* Crash if we weren't passed a valid function pointer. */ ++ ABORT_INSTRUCTION; ++ return 0; ++} diff --git a/SOURCES/glibc-rh2047981-20.patch b/SOURCES/glibc-rh2047981-20.patch new file mode 100644 index 0000000..bce1f3d --- /dev/null +++ b/SOURCES/glibc-rh2047981-20.patch @@ -0,0 +1,113 @@ +commit 0b98a8748759e88b58927882a8714109abe0a2d6 +Author: Adhemerval Zanella +Date: Thu Jul 22 17:10:57 2021 -0300 + + elf: Add _dl_audit_preinit + + It consolidates the code required to call la_preinit audit + callback. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +Conflicts: + csu/libc-start.c + Rework to existing init call code. + +diff --git a/csu/libc-start.c b/csu/libc-start.c +index fd0f8640eaeae34c..ae703cfa620163fd 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -265,32 +265,20 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + #ifdef SHARED + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0)) + GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]); +-#endif ++ + if (init) + (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM); + +-#ifdef SHARED + /* Auditing checkpoint: we have a new object. */ +- if (__glibc_unlikely (GLRO(dl_naudit) > 0)) +- { +- struct audit_ifaces *afct = GLRO(dl_audit); +- struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded; +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->preinit != NULL) +- afct->preinit (&link_map_audit_state (head, cnt)->cookie); +- +- afct = afct->next; +- } +- } +-#endif ++ _dl_audit_preinit (GL(dl_ns)[LM_ID_BASE]._ns_loaded); + +-#ifdef SHARED + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS)) + GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]); +-#endif + +-#ifndef SHARED ++#else /* !SHARED */ ++ if (init) ++ (*init) (argc, argv, __environ MAIN_AUXVEC_PARAM); ++ + _dl_debug_initialize (0, LM_ID_BASE); + #endif + #ifdef HAVE_CLEANUP_JMP_BUF +diff --git a/elf/Versions b/elf/Versions +index c5d4342cf1f5124c..35ac181bdb099af8 100644 +--- a/elf/Versions ++++ b/elf/Versions +@@ -59,7 +59,7 @@ ld { + _dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info; + _dl_deallocate_tls; _dl_make_stack_executable; + _dl_rtld_di_serinfo; _dl_starting_up; _dl_fatal_printf; +- _dl_audit_symbind_alt; ++ _dl_audit_symbind_alt; _dl_audit_preinit; + _rtld_global; _rtld_global_ro; + + # Only here for gdb while a better method is developed. +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index a21530f30bc5524b..0b6fac8e48877c93 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -108,6 +108,21 @@ _dl_audit_objclose (struct link_map *l) + } + } + ++void ++_dl_audit_preinit (struct link_map *l) ++{ ++ if (__glibc_likely (GLRO(dl_naudit) == 0)) ++ return; ++ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->preinit != NULL) ++ afct->preinit (&link_map_audit_state (l, cnt)->cookie); ++ afct = afct->next; ++ } ++} ++ + void + _dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref, void **value, + lookup_t result) +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index fa55c3bde10de52e..03676b474c3d37a3 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1295,6 +1295,9 @@ void _dl_audit_objopen (struct link_map *l, Lmid_t nsid) + void _dl_audit_objclose (struct link_map *l) + attribute_hidden; + ++/* Call the la_preinit from the audit modules for the link_map L. */ ++void _dl_audit_preinit (struct link_map *l); ++ + /* Call the la_symbind{32,64} from the audit modules for the link_map L. */ + void _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value, diff --git a/SOURCES/glibc-rh2047981-21.patch b/SOURCES/glibc-rh2047981-21.patch new file mode 100644 index 0000000..ea5003f --- /dev/null +++ b/SOURCES/glibc-rh2047981-21.patch @@ -0,0 +1,205 @@ +commit eff687e8462b0eaf65992a6031b54a4b1cd16796 +Author: Adhemerval Zanella +Date: Thu Jul 22 17:45:33 2021 -0300 + + elf: Add _dl_audit_pltenter + + It consolidates the code required to call la_pltenter audit + callback. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index 0b6fac8e48877c93..15250c67e8ac1658 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -17,7 +17,9 @@ + . */ + + #include ++#include + #include ++#include + + void + _dl_audit_activity_map (struct link_map *l, int action) +@@ -243,3 +245,78 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + reloc_result->flags = flags; + *value = DL_FIXUP_ADDR_VALUE (sym.st_value); + } ++ ++void ++_dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result, ++ DL_FIXUP_VALUE_TYPE *value, void *regs, long int *framesize) ++{ ++ /* Don't do anything if no auditor wants to intercept this call. */ ++ if (GLRO(dl_naudit) == 0 ++ || (reloc_result->enterexit & LA_SYMB_NOPLTENTER)) ++ return; ++ ++ /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been ++ initialized earlier in this function or in another thread. */ ++ assert (DL_FIXUP_VALUE_CODE_ADDR (*value) != 0); ++ ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, ++ l_info[DT_SYMTAB]) ++ + reloc_result->boundndx); ++ ++ /* Set up the sym parameter. */ ++ ElfW(Sym) sym = *defsym; ++ sym.st_value = DL_FIXUP_VALUE_ADDR (*value); ++ ++ /* Get the symbol name. */ ++ const char *strtab = (const void *) D_PTR (reloc_result->bound, ++ l_info[DT_STRTAB]); ++ const char *symname = strtab + sym.st_name; ++ ++ /* Keep track of overwritten addresses. */ ++ unsigned int flags = reloc_result->flags; ++ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->ARCH_LA_PLTENTER != NULL ++ && (reloc_result->enterexit ++ & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0) ++ { ++ long int new_framesize = -1; ++ struct auditstate *l_state = link_map_audit_state (l, cnt); ++ struct auditstate *bound_state ++ = link_map_audit_state (reloc_result->bound, cnt); ++ uintptr_t new_value ++ = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx, ++ &l_state->cookie, &bound_state->cookie, ++ regs, &flags, symname, &new_framesize); ++ if (new_value != (uintptr_t) sym.st_value) ++ { ++ flags |= LA_SYMB_ALTVALUE; ++ sym.st_value = new_value; ++ } ++ ++ /* Remember the results for every audit library and store a summary ++ in the first two bits. */ ++ reloc_result->enterexit |= ((flags & (LA_SYMB_NOPLTENTER ++ | LA_SYMB_NOPLTEXIT)) ++ << (2 * (cnt + 1))); ++ ++ if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT ++ << (2 * (cnt + 1)))) ++ == 0 && new_framesize != -1 && *framesize != -2) ++ { ++ /* If this is the first call providing information, use it. */ ++ if (*framesize == -1) ++ *framesize = new_framesize; ++ /* If two pltenter calls provide conflicting information, use ++ the larger value. */ ++ else if (new_framesize != *framesize) ++ *framesize = MAX (new_framesize, *framesize); ++ } ++ } ++ ++ afct = afct->next; ++ } ++ ++ *value = DL_FIXUP_ADDR_VALUE (sym.st_value); ++} +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index d4840a7c17441126..b46f7d7376e65361 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -319,78 +319,7 @@ _dl_profile_fixup ( + #ifdef SHARED + /* Auditing checkpoint: report the PLT entering and allow the + auditors to change the value. */ +- if (GLRO(dl_naudit) > 0 +- /* Don't do anything if no auditor wants to intercept this call. */ +- && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0) +- { +- /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been +- initialized earlier in this function or in another thread. */ +- assert (DL_FIXUP_VALUE_CODE_ADDR (value) != 0); +- ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, +- l_info[DT_SYMTAB]) +- + reloc_result->boundndx); +- +- /* Set up the sym parameter. */ +- ElfW(Sym) sym = *defsym; +- sym.st_value = DL_FIXUP_VALUE_ADDR (value); +- +- /* Get the symbol name. */ +- const char *strtab = (const void *) D_PTR (reloc_result->bound, +- l_info[DT_STRTAB]); +- const char *symname = strtab + sym.st_name; +- +- /* Keep track of overwritten addresses. */ +- unsigned int flags = reloc_result->flags; +- +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->ARCH_LA_PLTENTER != NULL +- && (reloc_result->enterexit +- & (LA_SYMB_NOPLTENTER << (2 * (cnt + 1)))) == 0) +- { +- long int new_framesize = -1; +- struct auditstate *l_state = link_map_audit_state (l, cnt); +- struct auditstate *bound_state +- = link_map_audit_state (reloc_result->bound, cnt); +- uintptr_t new_value +- = afct->ARCH_LA_PLTENTER (&sym, reloc_result->boundndx, +- &l_state->cookie, +- &bound_state->cookie, +- regs, &flags, symname, +- &new_framesize); +- if (new_value != (uintptr_t) sym.st_value) +- { +- flags |= LA_SYMB_ALTVALUE; +- sym.st_value = new_value; +- } +- +- /* Remember the results for every audit library and +- store a summary in the first two bits. */ +- reloc_result->enterexit +- |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) +- << (2 * (cnt + 1))); +- +- if ((reloc_result->enterexit & (LA_SYMB_NOPLTEXIT +- << (2 * (cnt + 1)))) +- == 0 && new_framesize != -1 && framesize != -2) +- { +- /* If this is the first call providing information, +- use it. */ +- if (framesize == -1) +- framesize = new_framesize; +- /* If two pltenter calls provide conflicting information, +- use the larger value. */ +- else if (new_framesize != framesize) +- framesize = MAX (new_framesize, framesize); +- } +- } +- +- afct = afct->next; +- } +- +- value = DL_FIXUP_ADDR_VALUE (sym.st_value); +- } ++ _dl_audit_pltenter (l, reloc_result, &value, regs, &framesize); + #endif + + /* Store the frame size information. */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 03676b474c3d37a3..47a9dee5b1c0ca63 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1307,6 +1307,10 @@ void _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + void _dl_audit_symbind_alt (struct link_map *l, const ElfW(Sym) *ref, + void **value, lookup_t result); + rtld_hidden_proto (_dl_audit_symbind_alt) ++void _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result, ++ DL_FIXUP_VALUE_TYPE *value, void *regs, ++ long int *framesize) ++ attribute_hidden; + #endif /* SHARED */ + + __END_DECLS diff --git a/SOURCES/glibc-rh2047981-22.patch b/SOURCES/glibc-rh2047981-22.patch new file mode 100644 index 0000000..17c35d5 --- /dev/null +++ b/SOURCES/glibc-rh2047981-22.patch @@ -0,0 +1,795 @@ +commit 8c0664e2b861fd3789602cc0b0b1922b0e20cb3a +Author: Adhemerval Zanella +Date: Thu Jul 22 18:02:42 2021 -0300 + + elf: Add _dl_audit_pltexit + + It consolidates the code required to call la_pltexit audit + callback. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +Conflicts: + nptl/tst-atfork4mod.c + sysdeps/powerpc/fpu/s_fmaf.S + sysdeps/powerpc/powerpc32/power4/multiarch/wcscpy-ppc32.c + sysdeps/powerpc/powerpc64/power5+/fpu/s_floor.S + Without d6d89608ac8cf2b37c75debad1fff653f6939f90 we + don't have dl-machine-rel.h so git picks a match for + all four files above, instead we modify dl-machine.h + for the targets: + sysdeps/i386/dl-machine.h + sysdeps/arm/dl-machine.h + sysdeps/mips/dl-machine.h + The fourth is the generic file and without it we + add the PLTREL macro to each target: + sysdeps/aarch64/dl-machine.h + sysdeps/powerpc/powerpc32/dl-machine.h + sysdeps/powerpc/powerpc64/dl-machine.h + sysdeps/s390/s390-32/dl-machine.h + sysdeps/s390/s390-64/dl-machine.h + sysdeps/x86_64/dl-machine.h + sysdeps/s390/s390-32/dl-trampoline.h + sysdeps/s390/s390-64/dl-trampoline.h + +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index 15250c67e8ac1658..152712b12fed6de2 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -20,6 +20,8 @@ + #include + #include + #include ++#include ++#include + + void + _dl_audit_activity_map (struct link_map *l, int action) +@@ -320,3 +322,48 @@ _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result, + + *value = DL_FIXUP_ADDR_VALUE (sym.st_value); + } ++ ++void ++DL_ARCH_FIXUP_ATTRIBUTE ++_dl_audit_pltexit (struct link_map *l, ElfW(Word) reloc_arg, ++ const void *inregs, void *outregs) ++{ ++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]); ++ ++ /* This is the address in the array where we store the result of previous ++ relocations. */ ++ // XXX Maybe the bound information must be stored on the stack since ++ // XXX with bind_not a new value could have been stored in the meantime. ++ struct reloc_result *reloc_result = ++ &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))]; ++ ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, ++ l_info[DT_SYMTAB]) ++ + reloc_result->boundndx); ++ ++ /* Set up the sym parameter. */ ++ ElfW(Sym) sym = *defsym; ++ sym.st_value = DL_FIXUP_VALUE_ADDR (reloc_result->addr); ++ ++ /* Get the symbol name. */ ++ const char *strtab = (const void *) D_PTR (reloc_result->bound, ++ l_info[DT_STRTAB]); ++ const char *symname = strtab + sym.st_name; ++ ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ if (afct->ARCH_LA_PLTEXIT != NULL ++ && (reloc_result->enterexit ++ & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0) ++ { ++ struct auditstate *l_state = link_map_audit_state (l, cnt); ++ struct auditstate *bound_state ++ = link_map_audit_state (reloc_result->bound, cnt); ++ afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx, ++ &l_state->cookie, &bound_state->cookie, ++ inregs, outregs, symname); ++ } ++ ++ afct = afct->next; ++ } ++} +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index b46f7d7376e65361..ec0b2164825fa538 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -16,8 +16,6 @@ + License along with the GNU C Library; if not, see + . */ + +-#define IN_DL_RUNTIME 1 /* This can be tested in dl-machine.h. */ +- + #include + #include + #include +@@ -30,19 +28,6 @@ + #include + + +-#if (!ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \ +- || ELF_MACHINE_NO_REL +-# define PLTREL ElfW(Rela) +-#else +-# define PLTREL ElfW(Rel) +-#endif +- +-/* The fixup functions might have need special attributes. If none +- are provided define the macro as empty. */ +-#ifndef ARCH_FIXUP_ATTRIBUTE +-# define ARCH_FIXUP_ATTRIBUTE +-#endif +- + /* This function is called through a special trampoline from the PLT the + first time each PLT entry is called. We must perform the relocation + specified in the PLT of the given shared object, and return the resolved +@@ -51,7 +36,7 @@ + function. */ + + DL_FIXUP_VALUE_TYPE +-attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE ++attribute_hidden __attribute ((noinline)) DL_ARCH_FIXUP_ATTRIBUTE + _dl_fixup ( + # ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS + ELF_MACHINE_RUNTIME_FIXUP_ARGS, +@@ -147,7 +132,8 @@ _dl_fixup ( + + #ifndef PROF + DL_FIXUP_VALUE_TYPE +-__attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE ++__attribute ((noinline)) ++DL_ARCH_FIXUP_ATTRIBUTE + _dl_profile_fixup ( + #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS + ELF_MACHINE_RUNTIME_FIXUP_ARGS, +@@ -331,52 +317,3 @@ _dl_profile_fixup ( + } + + #endif /* PROF */ +- +- +-#include +-void +-ARCH_FIXUP_ATTRIBUTE +-_dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg, +- const void *inregs, void *outregs) +-{ +-#ifdef SHARED +- const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]); +- +- /* This is the address in the array where we store the result of previous +- relocations. */ +- // XXX Maybe the bound information must be stored on the stack since +- // XXX with bind_not a new value could have been stored in the meantime. +- struct reloc_result *reloc_result = +- &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))]; +- ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, +- l_info[DT_SYMTAB]) +- + reloc_result->boundndx); +- +- /* Set up the sym parameter. */ +- ElfW(Sym) sym = *defsym; +- sym.st_value = DL_FIXUP_VALUE_ADDR (reloc_result->addr); +- +- /* Get the symbol name. */ +- const char *strtab = (const void *) D_PTR (reloc_result->bound, +- l_info[DT_STRTAB]); +- const char *symname = strtab + sym.st_name; +- +- struct audit_ifaces *afct = GLRO(dl_audit); +- for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) +- { +- if (afct->ARCH_LA_PLTEXIT != NULL +- && (reloc_result->enterexit +- & (LA_SYMB_NOPLTEXIT >> (2 * cnt))) == 0) +- { +- struct auditstate *l_state = link_map_audit_state (l, cnt); +- struct auditstate *bound_state +- = link_map_audit_state (reloc_result->bound, cnt); +- afct->ARCH_LA_PLTEXIT (&sym, reloc_result->boundndx, +- &l_state->cookie, &bound_state->cookie, +- inregs, outregs, symname); +- } +- +- afct = afct->next; +- } +-#endif +-} +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 3e5531138eaa18f8..e9943e889ef447ad 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -399,3 +399,11 @@ _dl_get_dl_main_map (void) + return &_dl_main_map; + } + #endif ++ ++/* This is used by _dl_runtime_profile, not used on static code. */ ++void ++DL_ARCH_FIXUP_ATTRIBUTE ++_dl_audit_pltexit (struct link_map *l, ElfW(Word) reloc_arg, ++ const void *inregs, void *outregs) ++{ ++} +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index 5eab544afe2717f7..c13d896a57811c7d 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -196,6 +196,7 @@ _dl_start_user: \n\ + /* AArch64 uses RELA not REL */ + #define ELF_MACHINE_NO_REL 1 + #define ELF_MACHINE_NO_RELA 0 ++#define PLTREL ElfW(Rela) + + #define DL_PLATFORM_INIT dl_platform_init () + +diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S +index a86d0722d4a0415b..18740398e63fdf97 100644 +--- a/sysdeps/aarch64/dl-trampoline.S ++++ b/sysdeps/aarch64/dl-trampoline.S +@@ -277,7 +277,7 @@ _dl_runtime_profile: + ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] + add x2, x29, #OFFSET_RG + add x3, x29, #OFFSET_RV +- bl _dl_call_pltexit ++ bl _dl_audit_pltexit + + ldp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0] + ldp d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0] +diff --git a/sysdeps/alpha/dl-trampoline.S b/sysdeps/alpha/dl-trampoline.S +index b326b37acedb5eaa..3acf5dec8d9585da 100644 +--- a/sysdeps/alpha/dl-trampoline.S ++++ b/sysdeps/alpha/dl-trampoline.S +@@ -187,7 +187,7 @@ _dl_runtime_profile_new: + jsr $26, ($27), 0 + ldgp $29, 0($26) + +- /* Set up for call to _dl_call_pltexit. */ ++ /* Set up for call to _dl_audit_pltexit. */ + ldq $16, 16*8($15) + ldq $17, 17*8($15) + stq $0, 16*8($15) +@@ -196,7 +196,7 @@ _dl_runtime_profile_new: + lda $19, 16*8($15) + stt $f0, 18*8($15) + stt $f1, 19*8($15) +- bsr $26, _dl_call_pltexit !samegp ++ bsr $26, _dl_audit_pltexit !samegp + + mov $15, $30 + cfi_def_cfa_register (30) +@@ -518,7 +518,7 @@ _dl_runtime_profile_old: + jsr $26, ($27), 0 + ldgp $29, 0($26) + +- /* Set up for call to _dl_call_pltexit. */ ++ /* Set up for call to _dl_audit_pltexit. */ + ldq $16, 48*8($15) + ldq $17, 49*8($15) + stq $0, 46*8($15) +@@ -527,7 +527,7 @@ _dl_runtime_profile_old: + lda $19, 46*8($15) + stt $f0, 48*8($15) + stt $f1, 49*8($15) +- bsr $26, _dl_call_pltexit !samegp ++ bsr $26, _dl_audit_pltexit !samegp + + mov $15, $30 + cfi_def_cfa_register (30) +diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h +index 1a4fd3f17b6df7da..9b5d0567df984c5d 100644 +--- a/sysdeps/arm/dl-machine.h ++++ b/sysdeps/arm/dl-machine.h +@@ -260,6 +260,8 @@ _dl_start_user:\n\ + Prelinked libraries may use Elf32_Rela though. */ + #define ELF_MACHINE_PLT_REL 1 + ++#define PLTREL ElfW(Rel) ++ + /* We define an initialization functions. This is called very early in + _dl_sysdep_start. */ + #define DL_PLATFORM_INIT dl_platform_init () +diff --git a/sysdeps/arm/dl-trampoline.S b/sysdeps/arm/dl-trampoline.S +index c731b012869a9cbc..ced1b1cb1017d677 100644 +--- a/sysdeps/arm/dl-trampoline.S ++++ b/sysdeps/arm/dl-trampoline.S +@@ -194,7 +194,7 @@ _dl_runtime_profile: + ldmia ip, {r0,r1} + add r2, r7, #72 + add r3, r7, #0 +- bl _dl_call_pltexit ++ bl _dl_audit_pltexit + + @ Return to caller. + ldmia r7, {r0-r3} +diff --git a/sysdeps/generic/dl-fixup-attribute.h b/sysdeps/generic/dl-fixup-attribute.h +new file mode 100644 +index 0000000000000000..aa92169b709b3fea +--- /dev/null ++++ b/sysdeps/generic/dl-fixup-attribute.h +@@ -0,0 +1,24 @@ ++/* ABI specifics for lazy resolution functions. ++ 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 ++ . */ ++ ++#ifndef _DL_FIXUP_ATTRIBUTE_H ++#define _DL_FIXUP_ATTRIBUTE_H ++ ++#define DL_ARCH_FIXUP_ATTRIBUTE ++ ++#endif +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 47a9dee5b1c0ca63..29b77b35175c1116 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1311,6 +1312,11 @@ void _dl_audit_pltenter (struct link_map *l, struct reloc_result *reloc_result, + DL_FIXUP_VALUE_TYPE *value, void *regs, + long int *framesize) + attribute_hidden; ++void DL_ARCH_FIXUP_ATTRIBUTE _dl_audit_pltexit (struct link_map *l, ++ ElfW(Word) reloc_arg, ++ const void *inregs, ++ void *outregs) ++ attribute_hidden; + #endif /* SHARED */ + + __END_DECLS +diff --git a/sysdeps/hppa/dl-runtime.c b/sysdeps/hppa/dl-runtime.c +index 2d061b150f0602c1..4c323131f937094b 100644 +--- a/sysdeps/hppa/dl-runtime.c ++++ b/sysdeps/hppa/dl-runtime.c +@@ -26,7 +26,7 @@ + _dl_fixup with the relocation offset. */ + + ElfW(Word) +-attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE ++attribute_hidden __attribute ((noinline)) DL_ARCH_FIXUP_ATTRIBUTE + _dl_fix_reloc_arg (struct fdesc *fptr, struct link_map *l) + { + Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type; +diff --git a/sysdeps/hppa/dl-trampoline.S b/sysdeps/hppa/dl-trampoline.S +index 7ee4331cc2e7deff..3c83c8542f4fc63f 100644 +--- a/sysdeps/hppa/dl-trampoline.S ++++ b/sysdeps/hppa/dl-trampoline.S +@@ -275,7 +275,7 @@ L(cont): + ldw -4(%sp),%r1 + copy %r1, %sp + +- /* Arguments to _dl_call_pltexit */ ++ /* Arguments to _dl_audit_pltexit */ + ldw -116(%sp), %r26 /* (1) got[1] == struct link_map */ + ldw -120(%sp), %r25 /* (2) reloc offsets */ + ldo -56(%sp), %r24 /* (3) *La_hppa_regs */ +@@ -287,8 +287,8 @@ L(cont): + ldo -128(%sp), %r1 + fstd %fr4,0(%r1) + +- /* Call _dl_call_pltexit */ +- bl _dl_call_pltexit,%rp ++ /* Call _dl_audit_pltexit */ ++ bl _dl_audit_pltexit,%rp + nop + + /* Restore *La_hppa_retval */ +diff --git a/sysdeps/i386/dl-fixup-attribute.h b/sysdeps/i386/dl-fixup-attribute.h +new file mode 100644 +index 0000000000000000..c10e9936f4db7254 +--- /dev/null ++++ b/sysdeps/i386/dl-fixup-attribute.h +@@ -0,0 +1,30 @@ ++/* ABI specifics for lazy resolution functions. i386 version. ++ 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 ++ . */ ++ ++#ifndef _DL_FIXUP_ATTRIBUTE_H ++#define _DL_FIXUP_ATTRIBUTE_H ++ ++/* We cannot use this scheme for profiling because the _mcount call destroys ++ the passed register information. */ ++#ifndef PROF ++# define DL_ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused)) ++#else ++# define DL_ARCH_FIXUP_ATTRIBUTE ++#endif ++ ++#endif +diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h +index 5ba95b9e4af49942..30c3464fc4ac19d8 100644 +--- a/sysdeps/i386/dl-machine.h ++++ b/sysdeps/i386/dl-machine.h +@@ -119,29 +119,6 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], + return lazy; + } + +-#ifdef IN_DL_RUNTIME +- +-# ifndef PROF +-/* We add a declaration of this function here so that in dl-runtime.c +- the ELF_MACHINE_RUNTIME_TRAMPOLINE macro really can pass the parameters +- in registers. +- +- We cannot use this scheme for profiling because the _mcount call +- destroys the passed register information. */ +-#define ARCH_FIXUP_ATTRIBUTE __attribute__ ((regparm (3), stdcall, unused)) +- +-extern ElfW(Addr) _dl_fixup (struct link_map *l, +- ElfW(Word) reloc_offset) +- ARCH_FIXUP_ATTRIBUTE; +-extern ElfW(Addr) _dl_profile_fixup (struct link_map *l, +- ElfW(Word) reloc_offset, +- ElfW(Addr) retaddr, void *regs, +- long int *framesizep) +- ARCH_FIXUP_ATTRIBUTE; +-# endif +- +-#endif +- + /* Mask identifying addresses reserved for the user program, + where the dynamic linker should not map anything. */ + #define ELF_MACHINE_USER_ADDRESS_MASK 0xf8000000UL +@@ -240,6 +217,8 @@ _dl_start_user:\n\ + Prelinked libraries may use Elf32_Rela though. */ + #define ELF_MACHINE_PLT_REL 1 + ++#define PLTREL ElfW(Rel) ++ + /* We define an initialization functions. This is called very early in + _dl_sysdep_start. */ + #define DL_PLATFORM_INIT dl_platform_init () +diff --git a/sysdeps/i386/dl-trampoline.S b/sysdeps/i386/dl-trampoline.S +index 6dc03192168ae2f3..a738b291a79bf8c2 100644 +--- a/sysdeps/i386/dl-trampoline.S ++++ b/sysdeps/i386/dl-trampoline.S +@@ -265,7 +265,7 @@ _dl_runtime_profile: + movl (LRV_SIZE + 4 + LR_SIZE)(%esp), %eax + # PLT1 + movl (LRV_SIZE + 4 + LR_SIZE + 4)(%esp), %edx +- call _dl_call_pltexit ++ call _dl_audit_pltexit + movl LRV_EAX_OFFSET(%esp), %eax + movl LRV_EDX_OFFSET(%esp), %edx + fldt LRV_ST1_OFFSET(%esp) +diff --git a/sysdeps/ia64/dl-trampoline.S b/sysdeps/ia64/dl-trampoline.S +index fc24c425bfe6907b..caeca3afcd7db6b6 100644 +--- a/sysdeps/ia64/dl-trampoline.S ++++ b/sysdeps/ia64/dl-trampoline.S +@@ -133,7 +133,7 @@ END(_dl_runtime_resolve) + + + /* The fourth argument to _dl_profile_fixup and the third one to +- _dl_call_pltexit are a pointer to La_ia64_regs: ++ _dl_audit_pltexit are a pointer to La_ia64_regs: + + 8byte r8 + 8byte r9 +@@ -159,7 +159,7 @@ END(_dl_runtime_resolve) + 8byte sp + + The fifth argument to _dl_profile_fixup is a pointer to long int. +- The fourth argument to _dl_call_pltexit is a pointer to ++ The fourth argument to _dl_audit_pltexit is a pointer to + La_ia64_retval: + + 8byte r8 +@@ -261,7 +261,7 @@ ENTRY(_dl_runtime_profile) + } + { .mii + mov r18 = ar.unat /* save it in La_ia64_regs */ +- mov loc7 = out3 /* save it for _dl_call_pltexit */ ++ mov loc7 = out3 /* save it for _dl_audit_pltexit */ + mov loc5 = r11 /* preserve language specific register */ + } + { .mmi +@@ -272,7 +272,7 @@ ENTRY(_dl_runtime_profile) + } + { .mii + mov ar.unat = r17 /* restore it for function call */ +- mov loc8 = r16 /* save it for _dl_call_pltexit */ ++ mov loc8 = r16 /* save it for _dl_audit_pltexit */ + nop.i 0x0 + } + { .mmi +@@ -291,7 +291,7 @@ ENTRY(_dl_runtime_profile) + { .mmi + stf.spill [r2] = f14, 32 + stf.spill [r3] = f15, 24 +- mov loc9 = out1 /* save it for _dl_call_pltexit */ ++ mov loc9 = out1 /* save it for _dl_audit_pltexit */ + ;; + } + { .mmb +@@ -426,7 +426,7 @@ ENTRY(_dl_runtime_profile) + br.call.sptk.many b0 = b6 + } + { .mii +- /* Prepare stack for _dl_call_pltexit. Loc10 has the original ++ /* Prepare stack for _dl_audit_pltexit. Loc10 has the original + stack pointer. */ + adds r12 = -PLTEXIT_FRAME_SIZE, loc10 + adds r2 = -(PLTEXIT_FRAME_SIZE - 16), loc10 +@@ -461,14 +461,14 @@ ENTRY(_dl_runtime_profile) + { .mmi + stf.spill [r2] = f12, 32 + stf.spill [r3] = f13, 32 +- /* We need to restore gp for _dl_call_pltexit. */ ++ /* We need to restore gp for _dl_audit_pltexit. */ + mov gp = loc11 + ;; + } + { .mmb + stf.spill [r2] = f14 + stf.spill [r3] = f15 +- br.call.sptk.many b0 = _dl_call_pltexit ++ br.call.sptk.many b0 = _dl_audit_pltexit + } + { .mmi + /* Load all the non-floating and floating return values. Skip +diff --git a/sysdeps/m68k/dl-trampoline.S b/sysdeps/m68k/dl-trampoline.S +index 7e1eace26b4a519d..27282ca8a6b1dada 100644 +--- a/sysdeps/m68k/dl-trampoline.S ++++ b/sysdeps/m68k/dl-trampoline.S +@@ -202,7 +202,7 @@ _dl_runtime_profile: + cfi_adjust_cfa_offset (4) + move.l (32+FPSPACE)(%sp), -(%sp) + cfi_adjust_cfa_offset (4) +- jbsr _dl_call_pltexit ++ jbsr _dl_audit_pltexit + lea 16(%sp), %sp + cfi_adjust_cfa_offset (-16) + move.l (%sp)+, %d0 +diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h +index b41e10647d81843b..d4bd8b62f4b036a3 100644 +--- a/sysdeps/mips/dl-machine.h ++++ b/sysdeps/mips/dl-machine.h +@@ -63,6 +63,7 @@ + #define ELF_MACHINE_PLT_REL 1 + #define ELF_MACHINE_NO_REL 0 + #define ELF_MACHINE_NO_RELA 0 ++#define PLTREL ElfW(Rel) + + /* Translate a processor specific dynamic tag to the index + in l_info array. */ +diff --git a/sysdeps/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h +index 31c7f3f95a2ce1b2..84322595793dc8bb 100644 +--- a/sysdeps/powerpc/powerpc32/dl-machine.h ++++ b/sysdeps/powerpc/powerpc32/dl-machine.h +@@ -150,6 +150,7 @@ __elf_preferred_address(struct link_map *loader, size_t maplength, + /* The PowerPC never uses REL relocations. */ + #define ELF_MACHINE_NO_REL 1 + #define ELF_MACHINE_NO_RELA 0 ++#define PLTREL ElfW(Rela) + + /* We define an initialization function to initialize HWCAP/HWCAP2 and + platform data so it can be copied into the TCB later. This is called +diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h +index 35996bb9173da231..3af1f708378f9a3c 100644 +--- a/sysdeps/powerpc/powerpc64/dl-machine.h ++++ b/sysdeps/powerpc/powerpc64/dl-machine.h +@@ -297,6 +297,7 @@ BODY_PREFIX "_dl_start_user:\n" \ + /* The PowerPC never uses REL relocations. */ + #define ELF_MACHINE_NO_REL 1 + #define ELF_MACHINE_NO_RELA 0 ++#define PLTREL ElfW(Rela) + + /* We define an initialization function to initialize HWCAP/HWCAP2 and + platform data so it can be copied into the TCB later. This is called +diff --git a/sysdeps/powerpc/powerpc64/dl-trampoline.S b/sysdeps/powerpc/powerpc64/dl-trampoline.S +index aa141dc44b980d9b..23290d32360507fd 100644 +--- a/sysdeps/powerpc/powerpc64/dl-trampoline.S ++++ b/sysdeps/powerpc/powerpc64/dl-trampoline.S +@@ -197,7 +197,7 @@ END(_dl_runtime_resolve) + #ifndef PROF + ENTRY (_dl_profile_resolve, 4) + /* Spill r30, r31 to preserve the link_map* and reloc_addr, in case we +- need to call _dl_call_pltexit. */ ++ need to call _dl_audit_pltexit. */ + std r31,-8(r1) + std r30,-16(r1) + /* We need to save the registers used to pass parameters, ie. r3 thru +@@ -452,7 +452,7 @@ L(restoreFXR2): + L(callpltexit): + addi r5,r1,INT_PARMS + addi r6,r1,INT_RTN +- bl JUMPTARGET(_dl_call_pltexit) ++ bl JUMPTARGET(_dl_audit_pltexit) + #ifndef SHARED + nop + #endif +diff --git a/sysdeps/s390/s390-32/dl-machine.h b/sysdeps/s390/s390-32/dl-machine.h +index ded41adff80346b6..2f3bb085ae2b6794 100644 +--- a/sysdeps/s390/s390-32/dl-machine.h ++++ b/sysdeps/s390/s390-32/dl-machine.h +@@ -279,6 +279,7 @@ _dl_start_user:\n\ + /* The S390 never uses Elf32_Rel relocations. */ + #define ELF_MACHINE_NO_REL 1 + #define ELF_MACHINE_NO_RELA 0 ++#define PLTREL ElfW(Rela) + + /* We define an initialization functions. This is called very early in + _dl_sysdep_start. */ +diff --git a/sysdeps/s390/s390-32/dl-trampoline.h b/sysdeps/s390/s390-32/dl-trampoline.h +index d36c002743bf2f0c..c447a41f067c462b 100644 +--- a/sysdeps/s390/s390-32/dl-trampoline.h ++++ b/sysdeps/s390/s390-32/dl-trampoline.h +@@ -207,7 +207,7 @@ _dl_runtime_profile: + basr %r1,0 + 5: l %r14,7f-5b(%r1) + la %r5,40(%r12) # pointer to struct La_s390_32_retval +- bas %r14,0(%r14,%r1) # call _dl_call_pltexit ++ bas %r14,0(%r14,%r1) # call _dl_audit_pltexit + + lr %r15,%r12 # remove stack frame + cfi_def_cfa_register (15) +@@ -224,7 +224,7 @@ _dl_runtime_profile: + br %r14 + + 6: .long _dl_profile_fixup - 0b +-7: .long _dl_call_pltexit - 5b ++7: .long _dl_audit_pltexit - 5b + cfi_endproc + .size _dl_runtime_profile, .-_dl_runtime_profile + #endif +diff --git a/sysdeps/s390/s390-64/dl-machine.h b/sysdeps/s390/s390-64/dl-machine.h +index 36327c40a1972dd7..033e7c9916e751f4 100644 +--- a/sysdeps/s390/s390-64/dl-machine.h ++++ b/sysdeps/s390/s390-64/dl-machine.h +@@ -228,6 +228,7 @@ _dl_start_user:\n\ + /* The 64 bit S/390 never uses Elf64_Rel relocations. */ + #define ELF_MACHINE_NO_REL 1 + #define ELF_MACHINE_NO_RELA 0 ++#define PLTREL ElfW(Rela) + + /* We define an initialization functions. This is called very early in + _dl_sysdep_start. */ +diff --git a/sysdeps/s390/s390-64/dl-trampoline.h b/sysdeps/s390/s390-64/dl-trampoline.h +index d313fd521db0b859..18534d629ebc00e2 100644 +--- a/sysdeps/s390/s390-64/dl-trampoline.h ++++ b/sysdeps/s390/s390-64/dl-trampoline.h +@@ -203,7 +203,7 @@ _dl_runtime_profile: + lmg %r2,%r4,48(%r12) # r2, r3: load arguments saved by PLT + # r4: pointer to struct La_s390_64_regs + la %r5,72(%r12) # pointer to struct La_s390_64_retval +- brasl %r14,_dl_call_pltexit ++ brasl %r14,_dl_audit_pltexit + + lgr %r15,%r12 # remove stack frame + cfi_def_cfa_register (15) +diff --git a/sysdeps/sh/dl-trampoline.S b/sysdeps/sh/dl-trampoline.S +index 0c8f84d26d3015ca..73f865f2af4e2d48 100644 +--- a/sysdeps/sh/dl-trampoline.S ++++ b/sysdeps/sh/dl-trampoline.S +@@ -423,8 +423,8 @@ _dl_runtime_profile: + .align 2 + #ifdef SHARED + 7: .long _GLOBAL_OFFSET_TABLE_ +-8: .long _dl_call_pltexit@GOTOFF ++8: .long _dl_audit_pltexit@GOTOFF + #else +-8: .long _dl_call_pltexit ++8: .long _dl_audit_pltexit + #endif + .size _dl_runtime_profile, .-_dl_runtime_profile +diff --git a/sysdeps/sparc/sparc32/dl-trampoline.S b/sysdeps/sparc/sparc32/dl-trampoline.S +index 098ffcfacc55d0b6..18ef2f0d3655b3de 100644 +--- a/sysdeps/sparc/sparc32/dl-trampoline.S ++++ b/sysdeps/sparc/sparc32/dl-trampoline.S +@@ -127,7 +127,7 @@ _dl_profile_invoke: + mov %l5, %o0 + mov %l6, %o1 + add %sp, (11 * 8), %o2 +- call _dl_call_pltexit ++ call _dl_audit_pltexit + add %sp, ( 9 * 8), %o3 + + ldd [%sp + ( 9 * 8)], %i0 +diff --git a/sysdeps/sparc/sparc64/dl-trampoline.S b/sysdeps/sparc/sparc64/dl-trampoline.S +index 4948b88b9640691d..9c18ceb131c9a25b 100644 +--- a/sysdeps/sparc/sparc64/dl-trampoline.S ++++ b/sysdeps/sparc/sparc64/dl-trampoline.S +@@ -196,7 +196,7 @@ _dl_profile_invoke: + mov %l5, %o0 + mov %l6, %o1 + add %sp, STACK_BIAS + (24 * 8), %o2 +- call _dl_call_pltexit ++ call _dl_audit_pltexit + add %sp, STACK_BIAS + (16 * 8), %o3 + + ldx [%sp + STACK_BIAS + (16 * 8)], %i0 +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index 5262aa69c06aa8db..d30317980882ac51 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -210,6 +210,7 @@ _dl_start_user:\n\ + /* The x86-64 never uses Elf64_Rel/Elf32_Rel relocations. */ + #define ELF_MACHINE_NO_REL 1 + #define ELF_MACHINE_NO_RELA 0 ++#define PLTREL ElfW(Rela) + + /* We define an initialization function. This is called very early in + _dl_sysdep_start. */ +diff --git a/sysdeps/x86_64/dl-runtime.h b/sysdeps/x86_64/dl-runtime.h +index 3fa61d7a4697cf3f..379f8bd4dea8ef97 100644 +--- a/sysdeps/x86_64/dl-runtime.h ++++ b/sysdeps/x86_64/dl-runtime.h +@@ -18,7 +18,7 @@ + 02111-1307 USA. */ + + /* The ABI calls for the PLT stubs to pass the index of the relocation +- and not its offset. In _dl_profile_fixup and _dl_call_pltexit we ++ and not its offset. In _dl_profile_fixup and _dl_audit_pltexit we + also use the index. Therefore it is wasteful to compute the offset + in the trampoline just to reverse the operation immediately + afterwards. */ +diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h +index a28b1e73a4b187ba..256dfbb64df9f03d 100644 +--- a/sysdeps/x86_64/dl-trampoline.h ++++ b/sysdeps/x86_64/dl-trampoline.h +@@ -388,7 +388,7 @@ _dl_runtime_profile: + jns 3f + + /* There's nothing in the frame size, so there +- will be no call to the _dl_call_pltexit. */ ++ will be no call to the _dl_audit_pltexit. */ + + /* Get back registers content. */ + movq LR_RCX_OFFSET(%rsp), %rcx +@@ -436,7 +436,7 @@ _dl_runtime_profile: + mov 24(%rbx), %RSP_LP # Drop the copied stack content + + /* Now we have to prepare the La_x86_64_retval structure for the +- _dl_call_pltexit. The La_x86_64_regs is being pointed by rsp now, ++ _dl_audit_pltexit. The La_x86_64_regs is being pointed by rsp now, + so we just need to allocate the sizeof(La_x86_64_retval) space on + the stack, since the alignment has already been taken care of. */ + # ifdef RESTORE_AVX +@@ -491,7 +491,7 @@ _dl_runtime_profile: + movq 24(%rbx), %rdx # La_x86_64_regs argument to %rdx. + movq 40(%rbx), %rsi # Copy args pushed by PLT in register. + movq 32(%rbx), %rdi # %rdi: link_map, %rsi: reloc_index +- call _dl_call_pltexit ++ call _dl_audit_pltexit + + /* Restore return registers. */ + movq LRV_RAX_OFFSET(%rsp), %rax diff --git a/SOURCES/glibc-rh2047981-23.patch b/SOURCES/glibc-rh2047981-23.patch new file mode 100644 index 0000000..b2e83f8 --- /dev/null +++ b/SOURCES/glibc-rh2047981-23.patch @@ -0,0 +1,449 @@ +Added $(objpfx)tst-audit19a: $(libdl) to elf/Makefile since +we still need $(libdl) in RHEL8. + +commit 063f9ba220f434c7f30dd65c4cff17c0c458a7cf +Author: Adhemerval Zanella +Date: Wed Jun 30 10:24:09 2021 -0300 + + elf: Avoid unnecessary slowdown from profiling with audit (BZ#15533) + + The rtld-audit interfaces introduces a slowdown due to enabling + profiling instrumentation (as if LD_AUDIT implied LD_PROFILE). + However, instrumenting is only necessary if one of audit libraries + provides PLT callbacks (la_pltenter or la_pltexit symbols). Otherwise, + the slowdown can be avoided. + + The following patch adjusts the logic that enables profiling to iterate + over all audit modules and check if any of those provides a PLT hook. + To keep la_symbind to work even without PLT callbacks, _dl_fixup now + calls the audit callback if the modules implements it. + + Co-authored-by: Alexander Monakov + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index 08a32a712a34f2cc..0cc03ffe2984ee50 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -221,12 +221,14 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-dlmopen-gethostbyname \ + tst-audit17 \ + tst-audit18 \ ++ tst-audit19b \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ + tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ + tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \ +- tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split ++ tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split \ ++ tst-audit19a + tests-container += tst-pldd tst-preload-pthread-libc + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +@@ -358,6 +360,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-dlmopen-gethostbyname-mod \ + tst-auditmod18 \ + tst-audit18mod \ ++ tst-auditmod19a \ ++ tst-auditmod19b \ ++ tst-audit19bmod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1548,6 +1553,14 @@ $(objpfx)tst-audit18.out: $(objpfx)tst-auditmod18.so \ + $(objpfx)tst-audit18mod.so + tst-audit18-ARGS = -- $(host-test-program-cmd) + ++$(objpfx)tst-audit19a: $(libdl) ++$(objpfx)tst-audit19a.out: $(objpfx)tst-auditmod19a.so ++tst-audit19a-ENV = LD_AUDIT=$(objpfx)tst-auditmod19a.so ++ ++$(objpfx)tst-audit19b.out: $(objpfx)tst-auditmod19b.so ++$(objpfx)tst-audit19b: $(objpfx)tst-audit19bmod.so ++tst-audit19b-ARGS = -- $(host-test-program-cmd) ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index 19de5de067a5ef07..7a84b1fa8c3a7fdd 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -178,12 +178,28 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + int skip_ifunc = reloc_mode & __RTLD_NOIFUNC; + + #ifdef SHARED ++ bool consider_symbind = false; + /* If we are auditing, install the same handlers we need for profiling. */ + if ((reloc_mode & __RTLD_AUDIT) == 0) +- consider_profiling |= GLRO(dl_audit) != NULL; ++ { ++ struct audit_ifaces *afct = GLRO(dl_audit); ++ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) ++ { ++ /* Profiling is needed only if PLT hooks are provided. */ ++ if (afct->ARCH_LA_PLTENTER != NULL ++ || afct->ARCH_LA_PLTEXIT != NULL) ++ consider_profiling = 1; ++ if (afct->symbind != NULL) ++ consider_symbind = true; ++ ++ afct = afct->next; ++ } ++ } + #elif defined PROF + /* Never use dynamic linker profiling for gprof profiling code. */ + # define consider_profiling 0 ++#else ++# define consider_symbind 0 + #endif + + if (l->l_relocated) +@@ -278,7 +294,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc); + + #ifndef PROF +- if (__glibc_unlikely (consider_profiling) ++ if ((consider_profiling || consider_symbind) + && l->l_info[DT_PLTRELSZ] != NULL) + { + /* Allocate the array which will contain the already found +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index ec0b2164825fa538..71ec65264ff780fb 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -123,6 +123,37 @@ _dl_fixup ( + && __builtin_expect (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC, 0)) + value = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (value)); + ++#ifdef SHARED ++ /* Auditing checkpoint: we have a new binding. Provide the auditing ++ libraries the possibility to change the value and tell us whether further ++ auditing is wanted. ++ The l_reloc_result is only allocated if there is an audit module which ++ provides a la_symbind. */ ++ if (l->l_reloc_result != NULL) ++ { ++ /* This is the address in the array where we store the result of previous ++ relocations. */ ++ struct reloc_result *reloc_result ++ = &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))]; ++ unsigned int init = atomic_load_acquire (&reloc_result->init); ++ if (init == 0) ++ { ++ _dl_audit_symbind (l, reloc_result, sym, &value, result); ++ ++ /* Store the result for later runs. */ ++ if (__glibc_likely (! GLRO(dl_bind_not))) ++ { ++ reloc_result->addr = value; ++ /* Guarantee all previous writes complete before init is ++ updated. See CONCURRENCY NOTES below. */ ++ atomic_store_release (&reloc_result->init, 1); ++ } ++ } ++ else ++ value = reloc_result->addr; ++ } ++#endif ++ + /* Finally, fix up the plt itself. */ + if (__glibc_unlikely (GLRO(dl_bind_not))) + return value; +diff --git a/elf/rtld.c b/elf/rtld.c +index 767acd122262b824..2994578ba3a5f911 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1027,13 +1027,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); + "la_objsearch\0" + "la_objopen\0" + "la_preinit\0" +-#if __ELF_NATIVE_CLASS == 32 +- "la_symbind32\0" +-#elif __ELF_NATIVE_CLASS == 64 +- "la_symbind64\0" +-#else +-# error "__ELF_NATIVE_CLASS must be defined" +-#endif ++ LA_SYMBIND "\0" + #define STRING(s) __STRING (s) + "la_" STRING (ARCH_LA_PLTENTER) "\0" + "la_" STRING (ARCH_LA_PLTEXIT) "\0" +diff --git a/elf/tst-audit19a.c b/elf/tst-audit19a.c +new file mode 100644 +index 0000000000000000..035cde9351c2711b +--- /dev/null ++++ b/elf/tst-audit19a.c +@@ -0,0 +1,38 @@ ++/* Check if DT_AUDIT a module without la_plt{enter,exit} symbols does not incur ++ in profiling (BZ#15533). ++ 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 ++ ++static int ++do_test (void) ++{ ++ void *h = xdlopen ("tst-auditmod19a.so", RTLD_NOW); ++ ++ struct link_map *lmap; ++ TEST_VERIFY_EXIT (dlinfo (h, RTLD_DI_LINKMAP, &lmap) == 0); ++ ++ /* The internal array is only allocated if profiling is enabled. */ ++ TEST_VERIFY (lmap->l_reloc_result == NULL); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit19b.c b/elf/tst-audit19b.c +new file mode 100644 +index 0000000000000000..da015734f24e0d79 +--- /dev/null ++++ b/elf/tst-audit19b.c +@@ -0,0 +1,94 @@ ++/* Check if DT_AUDIT a module with la_plt{enter,exit} call la_symbind ++ for lazy resolution. ++ 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 ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++int tst_audit18bmod1_func (void); ++ ++static int ++handle_restart (void) ++{ ++ TEST_COMPARE (tst_audit18bmod1_func (), 10); ++ return 0; ++} ++ ++static inline bool ++startswith (const char *str, const char *pre) ++{ ++ size_t lenpre = strlen (pre); ++ size_t lenstr = strlen (str); ++ return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0; ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ - One our fource parameters left if called initially: ++ + path to ld.so optional ++ + "--library-path" optional ++ + the library path optional ++ + the application name */ ++ ++ if (restart) ++ return handle_restart (); ++ ++ char *spargv[9]; ++ int i = 0; ++ for (; i < argc - 1; i++) ++ spargv[i] = argv[i + 1]; ++ spargv[i++] = (char *) "--direct"; ++ spargv[i++] = (char *) "--restart"; ++ spargv[i] = NULL; ++ ++ setenv ("LD_AUDIT", "tst-auditmod18b.so", 0); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit18b", 0, sc_allow_stderr); ++ ++ bool find_symbind = false; ++ ++ FILE *out = fmemopen (result.err.buffer, result.err.length, "r"); ++ TEST_VERIFY (out != NULL); ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ while (xgetline (&buffer, &buffer_length, out)) ++ if (startswith (buffer, "la_symbind: tst_audit18bmod1_func") == 0) ++ find_symbind = true; ++ ++ TEST_COMPARE (find_symbind, true); ++ ++ free (buffer); ++ xfclose (out); ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-audit19bmod.c b/elf/tst-audit19bmod.c +new file mode 100644 +index 0000000000000000..9ffdcd8f3ffbc38e +--- /dev/null ++++ b/elf/tst-audit19bmod.c +@@ -0,0 +1,23 @@ ++/* Extra module for tst-audit18b. ++ 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 ++ . */ ++ ++int ++tst_audit18bmod1_func (void) ++{ ++ return 10; ++} +diff --git a/elf/tst-auditmod19a.c b/elf/tst-auditmod19a.c +new file mode 100644 +index 0000000000000000..f58204099457743d +--- /dev/null ++++ b/elf/tst-auditmod19a.c +@@ -0,0 +1,25 @@ ++/* Audit module for tst-audit18a. ++ 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 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} +diff --git a/elf/tst-auditmod19b.c b/elf/tst-auditmod19b.c +new file mode 100644 +index 0000000000000000..e2248b2a75946746 +--- /dev/null ++++ b/elf/tst-auditmod19b.c +@@ -0,0 +1,46 @@ ++/* Audit module for tst-audit18b. ++ 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 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ return LA_FLG_BINDTO | LA_FLG_BINDFROM; ++} ++ ++uintptr_t ++#if __ELF_NATIVE_CLASS == 32 ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, unsigned int *flags, const char *symname) ++#else ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, unsigned int *flags, const char *symname) ++#endif ++{ ++ fprintf (stderr, "la_symbind: %s\n", symname); ++ return sym->st_value; ++} +diff --git a/include/link.h b/include/link.h +index cdd011f59445e490..dd491989beb41353 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -353,8 +353,10 @@ struct link_map + + #if __ELF_NATIVE_CLASS == 32 + # define symbind symbind32 ++# define LA_SYMBIND "la_symbind32" + #elif __ELF_NATIVE_CLASS == 64 + # define symbind symbind64 ++# define LA_SYMBIND "la_symbind64" + #else + # error "__ELF_NATIVE_CLASS must be defined" + #endif diff --git a/SOURCES/glibc-rh2047981-24.patch b/SOURCES/glibc-rh2047981-24.patch new file mode 100644 index 0000000..c6fc26a --- /dev/null +++ b/SOURCES/glibc-rh2047981-24.patch @@ -0,0 +1,296 @@ +Added $(libdl) to $(objpfx)tst-audit-tlsdesc-dlopen in elf/Makefile +since we still need $(libdl) in RHEL8. + +commit d1b38173c9255b1a4ae00018ad9b35404a7c74d0 +Author: Adhemerval Zanella +Date: Wed Jun 30 15:51:31 2021 -0300 + + elf: Add audit tests for modules with TLSDESC + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +diff --git a/elf/Makefile b/elf/Makefile +index 0cc03ffe2984ee50..d8d9734df0fea9a8 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -375,6 +375,22 @@ modules-names += tst-gnu2-tls1mod + $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so + tst-gnu2-tls1mod.so-no-z-defs = yes + CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2 ++ ++tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen ++modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc ++$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ ++ $(objpfx)tst-audit-tlsdesc-mod2.so \ ++ $(shared-thread-library) ++CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 ++CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 ++$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) $(libdl) ++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \ ++ $(objpfx)tst-audit-tlsdesc-mod2.so ++$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so ++$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so ++tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so ++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so ++tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so + endif + ifeq (yes,$(have-protected-data)) + modules-names += tst-protected1moda tst-protected1modb +diff --git a/elf/tst-audit-tlsdesc-dlopen.c b/elf/tst-audit-tlsdesc-dlopen.c +new file mode 100644 +index 0000000000000000..9c16bb087aca1b77 +--- /dev/null ++++ b/elf/tst-audit-tlsdesc-dlopen.c +@@ -0,0 +1,67 @@ ++/* DT_AUDIT with modules with TLSDESC. ++ 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 ++ ++static void * ++thr_func (void *mod) ++{ ++ int* (*get_global1)(void) = xdlsym (mod, "get_global1"); ++ int* (*get_global2)(void) = xdlsym (mod, "get_global2"); ++ void (*set_global2)(int) = xdlsym (mod, "set_global2"); ++ int* (*get_local1)(void) = xdlsym (mod, "get_local1"); ++ int* (*get_local2)(void) = xdlsym (mod, "get_local2"); ++ ++ int *global1 = get_global1 (); ++ TEST_COMPARE (*global1, 0); ++ ++*global1; ++ ++ int *global2 = get_global2 (); ++ TEST_COMPARE (*global2, 0); ++ ++*global2; ++ TEST_COMPARE (*global2, 1); ++ ++ set_global2 (10); ++ TEST_COMPARE (*global2, 10); ++ ++ int *local1 = get_local1 (); ++ TEST_COMPARE (*local1, 0); ++ ++*local1; ++ ++ int *local2 = get_local2 (); ++ TEST_COMPARE (*local2, 0); ++ ++*local2; ++ ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ void *mod = xdlopen ("tst-audit-tlsdesc-mod1.so", RTLD_LAZY); ++ ++ pthread_t thr = xpthread_create (NULL, thr_func, mod); ++ void *r = xpthread_join (thr); ++ TEST_VERIFY (r == NULL); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit-tlsdesc-mod1.c b/elf/tst-audit-tlsdesc-mod1.c +new file mode 100644 +index 0000000000000000..61c7dd99a2fb5e28 +--- /dev/null ++++ b/elf/tst-audit-tlsdesc-mod1.c +@@ -0,0 +1,41 @@ ++/* DT_AUDIT with modules with TLSDESC. ++ 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 ++ . */ ++ ++__thread int global1; ++ ++int * ++get_global1 (void) ++{ ++ return &global1; ++} ++ ++static __thread int local1; ++ ++void * ++get_local1 (void) ++{ ++ return &local1; ++} ++ ++extern __thread int global2; ++ ++void ++set_global2 (int v) ++{ ++ global2 = v; ++} +diff --git a/elf/tst-audit-tlsdesc-mod2.c b/elf/tst-audit-tlsdesc-mod2.c +new file mode 100644 +index 0000000000000000..28aef635f688ee03 +--- /dev/null ++++ b/elf/tst-audit-tlsdesc-mod2.c +@@ -0,0 +1,33 @@ ++/* DT_AUDIT with modules with TLSDESC. ++ 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 ++ . */ ++ ++__thread int global2; ++ ++int * ++get_global2 (void) ++{ ++ return &global2; ++} ++ ++static __thread int local2; ++ ++void * ++get_local2 (void) ++{ ++ return &local2; ++} +diff --git a/elf/tst-audit-tlsdesc.c b/elf/tst-audit-tlsdesc.c +new file mode 100644 +index 0000000000000000..3c8be81c95528f47 +--- /dev/null ++++ b/elf/tst-audit-tlsdesc.c +@@ -0,0 +1,60 @@ ++/* DT_AUDIT with modules with TLSDESC. ++ 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 ++ ++extern __thread int global1; ++extern __thread int global2; ++void *get_local1 (void); ++void set_global2 (int v); ++void *get_local2 (void); ++ ++static void * ++thr_func (void *clousure) ++{ ++ TEST_COMPARE (global1, 0); ++ ++global1; ++ TEST_COMPARE (global2, 0); ++ ++global2; ++ TEST_COMPARE (global2, 1); ++ ++ set_global2 (10); ++ TEST_COMPARE (global2, 10); ++ ++ int *local1 = get_local1 (); ++ TEST_COMPARE (*local1, 0); ++ ++*local1; ++ ++ int *local2 = get_local2 (); ++ TEST_COMPARE (*local2, 0); ++ ++*local2; ++ ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t thr = xpthread_create (NULL, thr_func, NULL); ++ void *r = xpthread_join (thr); ++ TEST_VERIFY (r == NULL); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-auditmod-tlsdesc.c b/elf/tst-auditmod-tlsdesc.c +new file mode 100644 +index 0000000000000000..e4b835d1f1fb6f73 +--- /dev/null ++++ b/elf/tst-auditmod-tlsdesc.c +@@ -0,0 +1,25 @@ ++/* DT_AUDIT with modules with TLSDESC. ++ 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 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} diff --git a/SOURCES/glibc-rh2047981-25.patch b/SOURCES/glibc-rh2047981-25.patch new file mode 100644 index 0000000..14cbb8d --- /dev/null +++ b/SOURCES/glibc-rh2047981-25.patch @@ -0,0 +1,313 @@ +commit f0e23d34a7bdf6b90fba954ee741419171ac41b2 +Author: Adhemerval Zanella +Date: Mon Jul 19 18:42:26 2021 -0300 + + elf: Issue audit la_objopen for vDSO + + The vDSO is is listed in the link_map chain, but is never the subject of + an la_objopen call. A new internal flag __RTLD_VDSO is added that + acts as __RTLD_OPENEXEC to allocate the required 'struct auditstate' + extra space for the 'struct link_map'. + + The return value from the callback is currently ignored, since there + is no PLT call involved by glibc when using the vDSO, neither the vDSO + are exported directly. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index d8d9734df0fea9a8..f047c1cce0c55da0 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -222,6 +222,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-audit17 \ + tst-audit18 \ + tst-audit19b \ ++ tst-audit22 \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -363,6 +364,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-auditmod19a \ + tst-auditmod19b \ + tst-audit19bmod \ ++ tst-auditmod22 \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1577,6 +1579,9 @@ $(objpfx)tst-audit19b.out: $(objpfx)tst-auditmod19b.so + $(objpfx)tst-audit19b: $(objpfx)tst-audit19bmod.so + tst-audit19b-ARGS = -- $(host-test-program-cmd) + ++$(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so ++tst-audit22-ARGS = -- $(host-test-program-cmd) ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/dl-object.c b/elf/dl-object.c +index 05a7750c65305771..3be309ecf1b5d4e2 100644 +--- a/elf/dl-object.c ++++ b/elf/dl-object.c +@@ -59,16 +59,19 @@ _dl_new_object (char *realname, const char *libname, int type, + { + #ifdef SHARED + unsigned int naudit; +- if (__glibc_unlikely ((mode & __RTLD_OPENEXEC) != 0)) ++ if (__glibc_unlikely ((mode & (__RTLD_OPENEXEC | __RTLD_VDSO)) != 0)) + { +- assert (type == lt_executable); +- assert (nsid == LM_ID_BASE); ++ if (mode & __RTLD_OPENEXEC) ++ { ++ assert (type == lt_executable); ++ assert (nsid == LM_ID_BASE); + +- /* Ignore the specified libname for the main executable. It is +- only known with an explicit loader invocation. */ +- libname = ""; ++ /* Ignore the specified libname for the main executable. It is ++ only known with an explicit loader invocation. */ ++ libname = ""; ++ } + +- /* We create the map for the executable before we know whether ++ /* We create the map for the executable and vDSO before we know whether + we have auditing libraries and if yes, how many. Assume the + worst. */ + naudit = DL_NNS; +diff --git a/elf/rtld.c b/elf/rtld.c +index 2994578ba3a5f911..efcbeac6c24c4b7b 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1917,6 +1917,12 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + assert (i == npreloads); + } + ++#ifdef NEED_DL_SYSINFO_DSO ++ /* Now that the audit modules are opened, call la_objopen for the vDSO. */ ++ if (GLRO(dl_sysinfo_map) != NULL) ++ _dl_audit_objopen (GLRO(dl_sysinfo_map), LM_ID_BASE); ++#endif ++ + /* Load all the libraries specified by DT_NEEDED entries. If LD_PRELOAD + specified some libraries to load, these are inserted before the actual + dependencies in the executable's searchlist for symbol resolution. */ +diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h +index 34b1d5e8c37c2610..d2b35a080b57c183 100644 +--- a/elf/setup-vdso.h ++++ b/elf/setup-vdso.h +@@ -30,7 +30,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + We just want our data structures to describe it as if we had just + mapped and relocated it normally. */ + struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL, +- 0, LM_ID_BASE); ++ __RTLD_VDSO, LM_ID_BASE); + if (__glibc_likely (l != NULL)) + { + static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro; +diff --git a/elf/tst-audit22.c b/elf/tst-audit22.c +new file mode 100644 +index 0000000000000000..18fd22a760ddc3d8 +--- /dev/null ++++ b/elf/tst-audit22.c +@@ -0,0 +1,124 @@ ++/* Check DTAUDIT and vDSO interaction. ++ 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++static uintptr_t vdso_addr; ++ ++static int ++handle_restart (void) ++{ ++ fprintf (stderr, "vdso: %p\n", (void*) vdso_addr); ++ return 0; ++} ++ ++static uintptr_t ++parse_address (const char *str) ++{ ++ void *r; ++ TEST_COMPARE (sscanf (str, "%p\n", &r), 1); ++ return (uintptr_t) r; ++} ++ ++static inline bool ++startswith (const char *str, const char *pre) ++{ ++ size_t lenpre = strlen (pre); ++ size_t lenstr = strlen (str); ++ return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0; ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ vdso_addr = getauxval (AT_SYSINFO_EHDR); ++ if (vdso_addr == 0) ++ FAIL_UNSUPPORTED ("getauxval (AT_SYSINFO_EHDR) returned 0"); ++ ++ /* We must have either: ++ - One our fource parameters left if called initially: ++ + path to ld.so optional ++ + "--library-path" optional ++ + the library path optional ++ + the application name */ ++ if (restart) ++ return handle_restart (); ++ ++ char *spargv[9]; ++ int i = 0; ++ for (; i < argc - 1; i++) ++ spargv[i] = argv[i + 1]; ++ spargv[i++] = (char *) "--direct"; ++ spargv[i++] = (char *) "--restart"; ++ spargv[i] = NULL; ++ ++ setenv ("LD_AUDIT", "tst-auditmod22.so", 0); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr); ++ ++ /* The respawned process should always print the vDSO address (otherwise it ++ will fails as unsupported). However, on some architectures the audit ++ module might see the vDSO with l_addr being 0, meaning a fixed mapping ++ (linux-gate.so). In this case we don't check its value against ++ AT_SYSINFO_EHDR one. */ ++ uintptr_t vdso_process = 0; ++ bool vdso_audit_found = false; ++ uintptr_t vdso_audit = 0; ++ ++ FILE *out = fmemopen (result.err.buffer, result.err.length, "r"); ++ TEST_VERIFY (out != NULL); ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ while (xgetline (&buffer, &buffer_length, out)) ++ { ++ if (startswith (buffer, "vdso: ")) ++ vdso_process = parse_address (buffer + strlen ("vdso: ")); ++ else if (startswith (buffer, "vdso found: ")) ++ { ++ vdso_audit = parse_address (buffer + strlen ("vdso found: ")); ++ vdso_audit_found = true; ++ } ++ } ++ ++ TEST_COMPARE (vdso_audit_found, true); ++ if (vdso_audit != 0) ++ TEST_COMPARE (vdso_process, vdso_audit); ++ ++ free (buffer); ++ xfclose (out); ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-auditmod22.c b/elf/tst-auditmod22.c +new file mode 100644 +index 0000000000000000..8e05ce8cbb215dd5 +--- /dev/null ++++ b/elf/tst-auditmod22.c +@@ -0,0 +1,51 @@ ++/* Check DTAUDIT and vDSO interaction. ++ 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 ++#include ++#include ++ ++static inline bool ++startswith (const char *str, const char *pre) ++{ ++ size_t lenpre = strlen (pre); ++ size_t lenstr = strlen (str); ++ return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0; ++} ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ /* The linux-gate.so is placed at a fixed address, thus l_addr being 0, ++ and it might be the value reported as the AT_SYSINFO_EHDR. */ ++ if (map->l_addr == 0 && startswith (map->l_name, "linux-gate.so")) ++ fprintf (stderr, "vdso found: %p\n", NULL); ++ else if (map->l_addr == getauxval (AT_SYSINFO_EHDR)) ++ fprintf (stderr, "vdso found: %p\n", (void*) map->l_addr); ++ ++ return 0; ++} +diff --git a/include/dlfcn.h b/include/dlfcn.h +index 109586a1d968b630..a39cc9c69f55a56a 100644 +--- a/include/dlfcn.h ++++ b/include/dlfcn.h +@@ -12,6 +12,8 @@ + #define __RTLD_AUDIT 0x08000000 + #define __RTLD_SECURE 0x04000000 /* Apply additional security checks. */ + #define __RTLD_NOIFUNC 0x02000000 /* Suppress calling ifunc functions. */ ++#define __RTLD_VDSO 0x01000000 /* Tell _dl_new_object the object is ++ system-loaded. */ + + #define __LM_ID_CALLER -2 + diff --git a/SOURCES/glibc-rh2047981-26.patch b/SOURCES/glibc-rh2047981-26.patch new file mode 100644 index 0000000..b05628f --- /dev/null +++ b/SOURCES/glibc-rh2047981-26.patch @@ -0,0 +1,170 @@ +Added $(objpfx)tst-auditmod20: $(libdl) in elf/Makefile since +we still have $(libdl) in RHEL8. + +commit 484e672ddabe0a919a692520e6ac8f2580866235 +Author: Adhemerval Zanella +Date: Wed Jun 30 17:33:57 2021 -0300 + + elf: Do not fail for failed dlmopen on audit modules (BZ #28061) + + The dl_main sets the LM_ID_BASE to RT_ADD just before starting to + add load new shared objects. The state is set to RT_CONSISTENT just + after all objects are loaded. + + However if a audit modules tries to dlmopen an inexistent module, + the _dl_open will assert that the namespace is in an inconsistent + state. + + This is different than dlopen, since first it will not use + LM_ID_BASE and second _dl_map_object_from_fd is the sole responsible + to set and reset the r_state value. + + So the assert on _dl_open can not really be seen if the state is + consistent, since _dt_main resets it. This patch removes the assert. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Florian Weimer + +Conflicts: + elf/dl-open.c + Uses dl_debug_initialize instead of dl_debug_update. + +diff --git a/elf/Makefile b/elf/Makefile +index f047c1cce0c55da0..7c7b9e1937d3e41c 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -222,6 +222,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-audit17 \ + tst-audit18 \ + tst-audit19b \ ++ tst-audit20 \ + tst-audit22 \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ +@@ -364,6 +365,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-auditmod19a \ + tst-auditmod19b \ + tst-audit19bmod \ ++ tst-auditmod20 \ + tst-auditmod22 \ + + # Most modules build with _ISOMAC defined, but those filtered out +@@ -1579,6 +1581,10 @@ $(objpfx)tst-audit19b.out: $(objpfx)tst-auditmod19b.so + $(objpfx)tst-audit19b: $(objpfx)tst-audit19bmod.so + tst-audit19b-ARGS = -- $(host-test-program-cmd) + ++$(objpfx)tst-audit20.out: $(objpfx)tst-auditmod20.so ++tst-audit20-ENV = LD_AUDIT=$(objpfx)tst-auditmod20.so ++$(objpfx)tst-auditmod20.so: $(libdl) ++ + $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so + tst-audit22-ARGS = -- $(host-test-program-cmd) + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 660a56b2fb2639cd..6b85e9ab4e249f86 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -911,8 +911,6 @@ no more namespaces available for dlmopen()")); + the flag here. */ + } + +- assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT); +- + /* Release the lock. */ + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + +diff --git a/elf/tst-audit20.c b/elf/tst-audit20.c +new file mode 100644 +index 0000000000000000..6f39ccee865b012b +--- /dev/null ++++ b/elf/tst-audit20.c +@@ -0,0 +1,25 @@ ++/* Check dlopen failure on audit modules. ++ 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 ++ . */ ++ ++static int ++do_test (void) ++{ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-auditmod20.c b/elf/tst-auditmod20.c +new file mode 100644 +index 0000000000000000..c57e50ee4e88dd6b +--- /dev/null ++++ b/elf/tst-auditmod20.c +@@ -0,0 +1,57 @@ ++/* Check dlopen failure on audit modules. ++ 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 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ return LAV_CURRENT; ++} ++ ++static void ++check (void) ++{ ++ { ++ void *mod = dlopen ("nonexistent.so", RTLD_NOW); ++ if (mod != NULL) ++ abort (); ++ } ++ ++ { ++ void *mod = dlmopen (LM_ID_BASE, "nonexistent.so", RTLD_NOW); ++ if (mod != NULL) ++ abort (); ++ } ++} ++ ++void ++la_activity (uintptr_t *cookie, unsigned int flag) ++{ ++ if (flag != LA_ACT_CONSISTENT) ++ return; ++ check (); ++} ++ ++void ++la_preinit (uintptr_t *cookie) ++{ ++ check (); ++} diff --git a/SOURCES/glibc-rh2047981-27.patch b/SOURCES/glibc-rh2047981-27.patch new file mode 100644 index 0000000..08f1448 --- /dev/null +++ b/SOURCES/glibc-rh2047981-27.patch @@ -0,0 +1,557 @@ +commit 28713c06129f8f64f88c423266e6ff2880216509 +Author: H.J. Lu +Date: Mon Dec 13 09:43:52 2021 -0800 + + elf: Sort tests and modules-names + + Sort tests and modules-names to reduce future conflicts. + +Conflicts: + elf/Makefile + Complete rewrite of sorted lists. + +diff --git a/elf/Makefile b/elf/Makefile +index 7c7b9e1937d3e41c..914cb5ad2f2c3aea 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -185,46 +185,130 @@ tests-static += tst-tls9-static + tst-tls9-static-ENV = \ + LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn + +-tests += restest1 preloadtest loadfail multiload origtest resolvfail \ +- constload1 order noload filter \ +- reldep reldep2 reldep3 reldep4 nodelete nodelete2 \ +- nodlopen nodlopen2 lateglobal initfirst global \ +- restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \ +- tst-tls4 tst-tls5 \ +- tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \ +- tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \ +- tst-align tst-align2 \ +- tst-dlmodcount tst-dlopenrpath tst-deep1 \ +- tst-dlmopen1 tst-dlmopen3 \ +- unload3 unload4 unload5 unload6 unload7 unload8 tst-global1 order2 \ +- tst-audit1 tst-audit2 tst-audit8 tst-audit9 \ +- tst-addr1 tst-thrlock \ +- tst-unique1 tst-unique2 $(if $(CXX),tst-unique3 tst-unique4 \ +- tst-nodelete tst-dlopen-nodelete-reloc) \ +- tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ +- tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ +- tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ +- tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ +- tst-debug1 tst-main1 tst-absolute-sym tst-absolute-zero tst-big-note \ +- tst-audit13 \ +- tst-sonamemove-link tst-sonamemove-dlopen \ +- tst-auditmany tst-initfinilazyfail \ +- tst-dlopenfail tst-dlopenfail-2 \ +- tst-filterobj tst-filterobj-dlopen tst-auxobj tst-auxobj-dlopen \ +- tst-audit14 tst-audit15 tst-audit16 \ +- tst-tls-ie tst-tls-ie-dlmopen \ +- argv0test \ +- tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ +- tst-tls20 tst-tls21 \ +- tst-rtld-run-static \ +- tst-dlmopen-dlerror \ +- tst-dlmopen-gethostbyname \ +- tst-audit17 \ +- tst-audit18 \ +- tst-audit19b \ +- tst-audit20 \ +- tst-audit22 \ ++tests += \ ++ argv0test \ ++ constload1 \ ++ dblload \ ++ dblunload \ ++ filter \ ++ global \ ++ initfirst \ ++ lateglobal \ ++ loadfail \ ++ multiload \ ++ next \ ++ nodelete \ ++ nodelete2 \ ++ nodlopen \ ++ nodlopen2 \ ++ noload \ ++ order \ ++ order2 \ ++ origtest \ ++ preloadtest \ ++ reldep \ ++ reldep2 \ ++ reldep3 \ ++ reldep4 \ ++ reldep5 \ ++ reldep6 \ ++ reldep7 \ ++ reldep8 \ ++ resolvfail \ ++ restest1 \ ++ restest2 \ ++ tst-absolute-sym \ ++ tst-absolute-zero \ ++ tst-addr1 \ ++ tst-align \ ++ tst-align2 \ ++ tst-audit1 \ ++ tst-audit11 \ ++ tst-audit12 \ ++ tst-audit13 \ ++ tst-audit14 \ ++ tst-audit15 \ ++ tst-audit16 \ ++ tst-audit17 \ ++ tst-audit18 \ ++ tst-audit19b \ ++ tst-audit2 \ ++ tst-audit20 \ ++ tst-audit22 \ ++ tst-audit8 \ ++ tst-audit9 \ ++ tst-auditmany \ ++ tst-auxobj \ ++ tst-auxobj-dlopen \ ++ tst-big-note \ ++ tst-debug1 \ ++ tst-deep1 \ ++ tst-dlmodcount \ ++ tst-dlmopen1 \ ++ tst-dlmopen3 \ ++ tst-dlmopen-dlerror \ ++ tst-dlmopen-gethostbyname \ ++ tst-dlopenfail \ ++ tst-dlopenfail-2 \ ++ tst-dlopenrpath \ ++ tst-dlsym-error \ ++ tst-filterobj \ ++ tst-filterobj-dlopen \ ++ tst-glibc-hwcaps \ ++ tst-glibc-hwcaps-mask \ ++ tst-glibc-hwcaps-prepend \ ++ tst-global1 \ ++ tst-initfinilazyfail \ ++ tst-initorder \ ++ tst-initorder2 \ ++ tst-latepthread \ ++ tst-main1 \ ++ tst-nodelete2 \ ++ tst-nodelete-dlclose \ ++ tst-nodelete-opened \ ++ tst-noload \ ++ tst-null-argv \ ++ tst-relsort1 \ ++ tst-rtld-run-static \ ++ tst-sonamemove-dlopen \ ++ tst-sonamemove-link \ ++ tst-thrlock \ ++ tst-tls10 \ ++ tst-tls11 \ ++ tst-tls12 \ ++ tst-tls13 \ ++ tst-tls14 \ ++ tst-tls15 \ ++ tst-tls16 \ ++ tst-tls17 \ ++ tst-tls18 \ ++ tst-tls19 \ ++ tst-tls20 \ ++ tst-tls21 \ ++ tst-tls4 \ ++ tst-tls5 \ ++ tst-tlsalign \ ++ tst-tlsalign-extern \ ++ tst-tls-dlinfo \ ++ tst-tls-ie \ ++ tst-tls-ie-dlmopen \ ++ tst-tls-manydynamic \ ++ tst-unique1 \ ++ tst-unique2 \ ++ unload3 \ ++ unload4 \ ++ unload5 \ ++ unload6 \ ++ unload7 \ ++ unload8 \ + # reldep9 ++tests-cxx = \ ++ tst-dlopen-nodelete-reloc \ ++ tst-nodelete \ ++ tst-unique3 \ ++ tst-unique4 \ ++ ++tests += $(if $(CXX),$(tests-cxx)) + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ + tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ +@@ -266,107 +350,269 @@ tst-tls-many-dynamic-modules-dep-bad = \ + extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \ + tst-tlsalign-vars.o + test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars +-modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ +- testobj1_1 failobj constload2 constload3 unloadmod \ +- dep1 dep2 dep3 dep4 vismod1 vismod2 vismod3 \ +- nodelmod1 nodelmod2 nodelmod3 nodelmod4 \ +- nodel2mod1 nodel2mod2 nodel2mod3 \ +- nodlopenmod nodlopenmod2 filtmod1 filtmod2 \ +- reldepmod1 reldepmod2 reldepmod3 reldepmod4 nextmod1 nextmod2 \ +- reldep4mod1 reldep4mod2 reldep4mod3 reldep4mod4 \ +- neededobj1 neededobj2 neededobj3 neededobj4 \ +- neededobj5 neededobj6 firstobj globalmod1 \ +- unload2mod unload2dep ltglobmod1 ltglobmod2 pathoptobj \ +- dblloadmod1 dblloadmod2 dblloadmod3 reldepmod5 reldepmod6 \ +- reldep6mod0 reldep6mod1 reldep6mod2 reldep6mod3 reldep6mod4 \ +- reldep7mod1 reldep7mod2 \ +- tst-tlsmod1 tst-tlsmod2 tst-tlsmod3 tst-tlsmod4 \ +- tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \ +- tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \ +- tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \ +- tst-tlsmod15a tst-tlsmod15b tst-tlsmod16a tst-tlsmod16b \ +- $(tlsmod17a-modules) tst-tlsmod17b $(tlsmod18a-modules) \ +- tst-tls19mod1 tst-tls19mod2 tst-tls19mod3 \ +- circlemod1 circlemod1a circlemod2 circlemod2a \ +- circlemod3 circlemod3a \ +- reldep8mod1 reldep8mod2 reldep8mod3 \ +- reldep9mod1 reldep9mod2 reldep9mod3 \ +- tst-alignmod tst-alignmod2 \ +- $(modules-execstack-$(have-z-execstack)) \ +- tst-dlopenrpathmod tst-deep1mod1 tst-deep1mod2 tst-deep1mod3 \ +- tst-dlmopen1mod tst-auditmod1 \ +- unload3mod1 unload3mod2 unload3mod3 unload3mod4 \ +- unload4mod1 unload4mod2 unload4mod3 unload4mod4 \ +- unload6mod1 unload6mod2 unload6mod3 \ +- unload7mod1 unload7mod2 \ +- unload8mod1 unload8mod1x unload8mod2 unload8mod3 \ +- order2mod1 order2mod2 order2mod3 order2mod4 \ +- tst-unique1mod1 tst-unique1mod2 \ +- tst-unique2mod1 tst-unique2mod2 \ +- tst-auditmod9a tst-auditmod9b \ +- $(if $(CXX),tst-unique3lib tst-unique3lib2 tst-unique4lib \ +- tst-nodelete-uniquemod tst-nodelete-rtldmod \ +- tst-nodelete-zmod \ +- tst-dlopen-nodelete-reloc-mod1 \ +- tst-dlopen-nodelete-reloc-mod2 \ +- tst-dlopen-nodelete-reloc-mod3 \ +- tst-dlopen-nodelete-reloc-mod4 \ +- tst-dlopen-nodelete-reloc-mod5 \ +- tst-dlopen-nodelete-reloc-mod6 \ +- tst-dlopen-nodelete-reloc-mod7 \ +- tst-dlopen-nodelete-reloc-mod8 \ +- tst-dlopen-nodelete-reloc-mod9 \ +- tst-dlopen-nodelete-reloc-mod10 \ +- tst-dlopen-nodelete-reloc-mod11 \ +- tst-dlopen-nodelete-reloc-mod12 \ +- tst-dlopen-nodelete-reloc-mod13 \ +- tst-dlopen-nodelete-reloc-mod14 \ +- tst-dlopen-nodelete-reloc-mod15 \ +- tst-dlopen-nodelete-reloc-mod16 \ +- tst-dlopen-nodelete-reloc-mod17) \ +- tst-initordera1 tst-initorderb1 \ +- tst-initordera2 tst-initorderb2 \ +- tst-initordera3 tst-initordera4 \ +- tst-initorder2a tst-initorder2b tst-initorder2c \ +- tst-initorder2d \ +- tst-relsort1mod1 tst-relsort1mod2 tst-array2dep \ +- tst-array5dep tst-null-argv-lib \ +- tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \ +- tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \ +- tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ +- tst-latepthreadmod $(tst-tls-many-dynamic-modules) \ +- $(tst-tls-many-dynamic-modules-dep) \ +- $(tst-tls-many-dynamic-modules-dep-bad) \ +- tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \ +- tst-main1mod tst-libc_dlvsym-dso tst-absolute-sym-lib \ +- tst-absolute-zero-lib tst-big-note-lib \ +- tst-audit13mod1 tst-sonamemove-linkmod1 \ +- tst-sonamemove-runmod1 tst-sonamemove-runmod2 \ +- tst-auditmanymod1 tst-auditmanymod2 tst-auditmanymod3 \ +- tst-auditmanymod4 tst-auditmanymod5 tst-auditmanymod6 \ +- tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \ +- tst-initlazyfailmod tst-finilazyfailmod \ +- tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \ +- tst-dlopenfailmod3 \ +- tst-filterobj-flt tst-filterobj-aux tst-filterobj-filtee \ +- tst-auditlogmod-1 tst-auditlogmod-2 tst-auditlogmod-3 \ +- tst-tls-ie-mod0 tst-tls-ie-mod1 tst-tls-ie-mod2 \ +- tst-tls-ie-mod3 tst-tls-ie-mod4 tst-tls-ie-mod5 \ +- tst-tls-ie-mod6 libmarkermod1-1 libmarkermod1-2 libmarkermod1-3 \ +- libmarkermod2-1 libmarkermod2-2 \ +- libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \ +- libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ +- libmarkermod5-1 libmarkermod5-2 libmarkermod5-3 libmarkermod5-4 \ +- libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \ +- tst-dlmopen-dlerror-mod \ +- tst-dlmopen-gethostbyname-mod \ +- tst-auditmod18 \ +- tst-audit18mod \ +- tst-auditmod19a \ +- tst-auditmod19b \ +- tst-audit19bmod \ +- tst-auditmod20 \ +- tst-auditmod22 \ ++modules-names = \ ++ circlemod1 \ ++ circlemod1a \ ++ circlemod2 \ ++ circlemod2a \ ++ circlemod3 \ ++ circlemod3a \ ++ constload2 \ ++ constload3 \ ++ dblloadmod1 \ ++ dblloadmod2 \ ++ dblloadmod3 \ ++ dep1 \ ++ dep2 \ ++ dep3 \ ++ dep4 \ ++ failobj \ ++ filtmod1 \ ++ filtmod2 \ ++ firstobj \ ++ globalmod1 \ ++ libmarkermod1-1 \ ++ libmarkermod1-2 \ ++ libmarkermod1-3 \ ++ libmarkermod2-1 \ ++ libmarkermod2-2 \ ++ libmarkermod3-1 \ ++ libmarkermod3-2 \ ++ libmarkermod3-3 \ ++ libmarkermod4-1 \ ++ libmarkermod4-2 \ ++ libmarkermod4-3 \ ++ libmarkermod4-4 \ ++ libmarkermod5-1 \ ++ libmarkermod5-2 \ ++ libmarkermod5-3 \ ++ libmarkermod5-4 \ ++ libmarkermod5-5 \ ++ ltglobmod1 \ ++ ltglobmod2 \ ++ neededobj1 \ ++ neededobj2 \ ++ neededobj3 \ ++ neededobj4 \ ++ neededobj5 \ ++ neededobj6 \ ++ nextmod1 \ ++ nextmod2 \ ++ nodel2mod1 \ ++ nodel2mod2 \ ++ nodel2mod3 \ ++ nodelmod1 \ ++ nodelmod2 \ ++ nodelmod3 \ ++ nodelmod4 \ ++ nodlopenmod \ ++ nodlopenmod2 \ ++ order2mod1 \ ++ order2mod2 \ ++ order2mod3 \ ++ order2mod4 \ ++ pathoptobj \ ++ reldep4mod1 \ ++ reldep4mod2 \ ++ reldep4mod3 \ ++ reldep4mod4 \ ++ reldep6mod0 \ ++ reldep6mod1 \ ++ reldep6mod2 \ ++ reldep6mod3 \ ++ reldep6mod4 \ ++ reldep7mod1 \ ++ reldep7mod2 \ ++ reldep8mod1 \ ++ reldep8mod2 \ ++ reldep8mod3 \ ++ reldep9mod1 \ ++ reldep9mod2 \ ++ reldep9mod3 \ ++ reldepmod1 \ ++ reldepmod2 \ ++ reldepmod3 \ ++ reldepmod4 \ ++ reldepmod5 \ ++ reldepmod6 \ ++ testobj1 \ ++ testobj1_1 \ ++ testobj2 \ ++ testobj3 \ ++ testobj4 \ ++ testobj5 \ ++ testobj6 \ ++ tst-absolute-sym-lib \ ++ tst-absolute-zero-lib \ ++ tst-alignmod \ ++ tst-alignmod2 \ ++ tst-array2dep \ ++ tst-array5dep \ ++ tst-audit11mod1 \ ++ tst-audit11mod2 \ ++ tst-audit12mod1 \ ++ tst-audit12mod2 \ ++ tst-audit12mod3 \ ++ tst-audit13mod1 \ ++ tst-audit18mod \ ++ tst-audit19bmod \ ++ tst-auditlogmod-1 \ ++ tst-auditlogmod-2 \ ++ tst-auditlogmod-3 \ ++ tst-auditmanymod1 \ ++ tst-auditmanymod2 \ ++ tst-auditmanymod3 \ ++ tst-auditmanymod4 \ ++ tst-auditmanymod5 \ ++ tst-auditmanymod6 \ ++ tst-auditmanymod7 \ ++ tst-auditmanymod8 \ ++ tst-auditmanymod9 \ ++ tst-auditmod1 \ ++ tst-auditmod9a \ ++ tst-auditmod9b \ ++ tst-auditmod11 \ ++ tst-auditmod12 \ ++ tst-auditmod18 \ ++ tst-auditmod19a \ ++ tst-auditmod19b \ ++ tst-auditmod20 \ ++ tst-auditmod22 \ ++ tst-big-note-lib \ ++ tst-deep1mod1 \ ++ tst-deep1mod2 \ ++ tst-deep1mod3 \ ++ tst-dlmopen1mod \ ++ tst-dlmopen-dlerror-mod \ ++ tst-dlmopen-gethostbyname-mod \ ++ tst-dlopenfaillinkmod \ ++ tst-dlopenfailmod1 \ ++ tst-dlopenfailmod2 \ ++ tst-dlopenfailmod3 \ ++ tst-dlopenrpathmod \ ++ tst-filterobj-aux \ ++ tst-filterobj-filtee \ ++ tst-filterobj-flt \ ++ tst-finilazyfailmod \ ++ tst-initlazyfailmod \ ++ tst-initorder2a \ ++ tst-initorder2b \ ++ tst-initorder2c \ ++ tst-initorder2d \ ++ tst-initordera1 \ ++ tst-initordera2 \ ++ tst-initordera3 \ ++ tst-initordera4 \ ++ tst-initorderb1 \ ++ tst-initorderb2 \ ++ tst-latepthreadmod \ ++ tst-libc_dlvsym-dso \ ++ tst-main1mod \ ++ tst-nodelete2mod \ ++ tst-nodelete-dlclose-dso \ ++ tst-nodelete-dlclose-plugin \ ++ tst-nodelete-opened-lib \ ++ tst-null-argv-lib \ ++ tst-relsort1mod1 \ ++ tst-relsort1mod2 \ ++ tst-sonamemove-linkmod1 \ ++ tst-sonamemove-runmod1 \ ++ tst-sonamemove-runmod2 \ ++ tst-tls19mod1 \ ++ tst-tls19mod2 \ ++ tst-tls19mod3 \ ++ tst-tls20mod-bad \ ++ tst-tls21mod \ ++ tst-tlsalign-lib \ ++ tst-tls-ie-mod0 \ ++ tst-tls-ie-mod1 \ ++ tst-tls-ie-mod2 \ ++ tst-tls-ie-mod3 \ ++ tst-tls-ie-mod4 \ ++ tst-tls-ie-mod5 \ ++ tst-tls-ie-mod6 \ ++ tst-tlsmod1 \ ++ tst-tlsmod10 \ ++ tst-tlsmod11 \ ++ tst-tlsmod12 \ ++ tst-tlsmod13 \ ++ tst-tlsmod13a \ ++ tst-tlsmod14a \ ++ tst-tlsmod14b \ ++ tst-tlsmod15a \ ++ tst-tlsmod15b \ ++ tst-tlsmod16a \ ++ tst-tlsmod16b \ ++ tst-tlsmod17b \ ++ tst-tlsmod2 \ ++ tst-tlsmod3 \ ++ tst-tlsmod4 \ ++ tst-tlsmod5 \ ++ tst-tlsmod6 \ ++ tst-tlsmod7 \ ++ tst-tlsmod8 \ ++ tst-tlsmod9 \ ++ tst-unique1mod1 \ ++ tst-unique1mod2 \ ++ tst-unique2mod1 \ ++ tst-unique2mod2 \ ++ unload2dep \ ++ unload2mod \ ++ unload3mod1 \ ++ unload3mod2 \ ++ unload3mod3 \ ++ unload3mod4 \ ++ unload4mod1 \ ++ unload4mod2 \ ++ unload4mod3 \ ++ unload4mod4 \ ++ unload6mod1 \ ++ unload6mod2 \ ++ unload6mod3 \ ++ unload7mod1 \ ++ unload7mod2 \ ++ unload8mod1 \ ++ unload8mod1x \ ++ unload8mod2 \ ++ unload8mod3 \ ++ unloadmod \ ++ vismod1 \ ++ vismod2 \ ++ vismod3 \ ++ ++modules-names-cxx = \ ++ tst-dlopen-nodelete-reloc-mod1 \ ++ tst-dlopen-nodelete-reloc-mod10 \ ++ tst-dlopen-nodelete-reloc-mod11 \ ++ tst-dlopen-nodelete-reloc-mod12 \ ++ tst-dlopen-nodelete-reloc-mod13 \ ++ tst-dlopen-nodelete-reloc-mod14 \ ++ tst-dlopen-nodelete-reloc-mod15 \ ++ tst-dlopen-nodelete-reloc-mod16 \ ++ tst-dlopen-nodelete-reloc-mod17 \ ++ tst-dlopen-nodelete-reloc-mod2 \ ++ tst-dlopen-nodelete-reloc-mod3 \ ++ tst-dlopen-nodelete-reloc-mod4 \ ++ tst-dlopen-nodelete-reloc-mod5 \ ++ tst-dlopen-nodelete-reloc-mod6 \ ++ tst-dlopen-nodelete-reloc-mod7 \ ++ tst-dlopen-nodelete-reloc-mod8 \ ++ tst-dlopen-nodelete-reloc-mod9 \ ++ tst-nodelete-rtldmod \ ++ tst-nodelete-uniquemod \ ++ tst-nodelete-zmod \ ++ tst-unique3lib \ ++ tst-unique3lib2 \ ++ tst-unique4lib \ ++ ++modules-names += \ ++ $(if $(CXX),$(modules-names-cxx)) \ ++ $(modules-execstack-$(have-z-execstack)) \ ++ $(tst-tls-many-dynamic-modules) \ ++ $(tst-tls-many-dynamic-modules-dep) \ ++ $(tst-tls-many-dynamic-modules-dep-bad) \ ++ $(tlsmod17a-modules) \ ++ $(tlsmod18a-modules) \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. diff --git a/SOURCES/glibc-rh2047981-28.patch b/SOURCES/glibc-rh2047981-28.patch new file mode 100644 index 0000000..9fb9d98 --- /dev/null +++ b/SOURCES/glibc-rh2047981-28.patch @@ -0,0 +1,77 @@ +commit bfb5ed5df3dd4d9507b4922248dc445b690d19c0 +Author: H.J. Lu +Date: Fri Oct 15 10:44:49 2021 -0700 + + elf: Also try DT_RUNPATH for LD_AUDIT dlopen [BZ #28455] + + DT_RUNPATH is only used to find the immediate dependencies of the + executable or shared object containing the DT_RUNPATH entry. Update + LD_AUDIT dlopen call to try the DT_RUNPATH entry of the executable. + + Add tst-audit14a, which is copied from tst-audit14, to DT_RUNPATH and + build tst-audit14 with -Wl,--disable-new-dtags to test DT_RPATH. + + This partially fixes BZ #28455. + +Conflicts: + elf/Makefile + Rewrite test inclusion to use older stdout pattern. + +diff --git a/elf/Makefile b/elf/Makefile +index 914cb5ad2f2c3aea..4ec4e9a049156755 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -227,6 +227,7 @@ tests += \ + tst-audit12 \ + tst-audit13 \ + tst-audit14 \ ++ tst-audit14a \ + tst-audit15 \ + tst-audit16 \ + tst-audit17 \ +@@ -1788,9 +1789,11 @@ $(objpfx)tst-auditmany.out: $(objpfx)tst-auditmanymod1.so \ + tst-auditmany-ENV = \ + LD_AUDIT=tst-auditmanymod1.so:tst-auditmanymod2.so:tst-auditmanymod3.so:tst-auditmanymod4.so:tst-auditmanymod5.so:tst-auditmanymod6.so:tst-auditmanymod7.so:tst-auditmanymod8.so:tst-auditmanymod9.so + +-LDFLAGS-tst-audit14 = -Wl,--audit=tst-auditlogmod-1.so ++LDFLAGS-tst-audit14 = -Wl,--audit=tst-auditlogmod-1.so,--disable-new-dtags + $(objpfx)tst-auditlogmod-1.so: $(libsupport) + $(objpfx)tst-audit14.out: $(objpfx)tst-auditlogmod-1.so ++LDFLAGS-tst-audit14a = -Wl,--audit=tst-auditlogmod-1.so,--enable-new-dtags ++$(objpfx)tst-audit14a.out: $(objpfx)tst-auditlogmod-1.so + LDFLAGS-tst-audit15 = \ + -Wl,--audit=tst-auditlogmod-1.so,--depaudit=tst-auditlogmod-2.so + $(objpfx)tst-auditlogmod-2.so: $(libsupport) +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 1613217a236c7fc3..0b45e6e3db31c70d 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -2042,6 +2042,21 @@ _dl_map_object (struct link_map *loader, const char *name, + &main_map->l_rpath_dirs, + &realname, &fb, loader ?: main_map, LA_SER_RUNPATH, + &found_other_class); ++ ++ /* Also try DT_RUNPATH in the executable for LD_AUDIT dlopen ++ call. */ ++ if (__glibc_unlikely (mode & __RTLD_AUDIT) ++ && fd == -1 && !did_main_map ++ && main_map != NULL && main_map->l_type != lt_loaded) ++ { ++ struct r_search_path_struct l_rpath_dirs; ++ l_rpath_dirs.dirs = NULL; ++ if (cache_rpath (main_map, &l_rpath_dirs, ++ DT_RUNPATH, "RUNPATH")) ++ fd = open_path (name, namelen, mode, &l_rpath_dirs, ++ &realname, &fb, loader ?: main_map, ++ LA_SER_RUNPATH, &found_other_class); ++ } + } + + /* Try the LD_LIBRARY_PATH environment variable. */ +diff --git a/elf/tst-audit14a.c b/elf/tst-audit14a.c +new file mode 100644 +index 0000000000000000..c6232eacf2946e4e +--- /dev/null ++++ b/elf/tst-audit14a.c +@@ -0,0 +1 @@ ++#include "tst-audit14.c" diff --git a/SOURCES/glibc-rh2047981-29.patch b/SOURCES/glibc-rh2047981-29.patch new file mode 100644 index 0000000..3581baa --- /dev/null +++ b/SOURCES/glibc-rh2047981-29.patch @@ -0,0 +1,42 @@ +commit f4f70c2895e3d325188a42c10eb7bb4335be6773 +Author: H.J. Lu +Date: Tue Jan 4 06:58:34 2022 -0800 + + elf: Add a comment after trailing backslashes + +diff --git a/elf/Makefile b/elf/Makefile +index 4ec4e9a049156755..53faca4585220048 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -308,6 +308,7 @@ tests-cxx = \ + tst-nodelete \ + tst-unique3 \ + tst-unique4 \ ++# tests-cxx + + tests += $(if $(CXX),$(tests-cxx)) + tests-internal += loadtest unload unload2 circleload1 \ +@@ -580,6 +581,7 @@ modules-names = \ + vismod1 \ + vismod2 \ + vismod3 \ ++# modules-names + + modules-names-cxx = \ + tst-dlopen-nodelete-reloc-mod1 \ +@@ -605,6 +607,7 @@ modules-names-cxx = \ + tst-unique3lib \ + tst-unique3lib2 \ + tst-unique4lib \ ++# modules-names-cxx + + modules-names += \ + $(if $(CXX),$(modules-names-cxx)) \ +@@ -614,6 +617,7 @@ modules-names += \ + $(tst-tls-many-dynamic-modules-dep-bad) \ + $(tlsmod17a-modules) \ + $(tlsmod18a-modules) \ ++# modules-names + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. diff --git a/SOURCES/glibc-rh2047981-3.patch b/SOURCES/glibc-rh2047981-3.patch new file mode 100644 index 0000000..aa0aaaf --- /dev/null +++ b/SOURCES/glibc-rh2047981-3.patch @@ -0,0 +1,245 @@ +commit 8dbb7a08ec52057819db4ee234f9429ab99eb4ae +Author: Vineet Gupta +Date: Wed May 27 12:54:21 2020 -0700 + + dl-runtime: reloc_{offset,index} now functions arch overide'able + + The existing macros are fragile and expect local variables with a + certain name. Fix this by defining them as functions with default + implementation in a new header dl-runtime.h which arches can override + if need be. + + This came up during ARC port review, hence the need for argument pltgot + in reloc_index() which is not needed by existing ports. + + This patch potentially only affects hppa/x86 ports, + build tested for both those configs and a few more. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index 72b03e000dcf190e..4ccd7c30678fafad 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -27,6 +27,7 @@ + #include "dynamic-link.h" + #include + #include ++#include + + + #if (!ELF_MACHINE_NO_RELA && !defined ELF_MACHINE_PLT_REL) \ +@@ -42,13 +43,6 @@ + # define ARCH_FIXUP_ATTRIBUTE + #endif + +-#ifndef reloc_offset +-# define reloc_offset reloc_arg +-# define reloc_index reloc_arg / sizeof (PLTREL) +-#endif +- +- +- + /* This function is called through a special trampoline from the PLT the + first time each PLT entry is called. We must perform the relocation + specified in the PLT of the given shared object, and return the resolved +@@ -68,8 +62,11 @@ _dl_fixup ( + = (const void *) D_PTR (l, l_info[DT_SYMTAB]); + const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]); + ++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]); ++ + const PLTREL *const reloc +- = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset); ++ = (const void *) (D_PTR (l, l_info[DT_JMPREL]) ++ + reloc_offset (pltgot, reloc_arg)); + const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; + const ElfW(Sym) *refsym = sym; + void *const rel_addr = (void *)(l->l_addr + reloc->r_offset); +@@ -180,9 +177,12 @@ _dl_profile_fixup ( + l, reloc_arg); + } + ++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]); ++ + /* This is the address in the array where we store the result of previous + relocations. */ +- struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index]; ++ struct reloc_result *reloc_result ++ = &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))]; + + /* CONCURRENCY NOTES: + +@@ -219,8 +219,11 @@ _dl_profile_fixup ( + = (const void *) D_PTR (l, l_info[DT_SYMTAB]); + const char *strtab = (const char *) D_PTR (l, l_info[DT_STRTAB]); + ++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]); ++ + const PLTREL *const reloc +- = (const void *) (D_PTR (l, l_info[DT_JMPREL]) + reloc_offset); ++ = (const void *) (D_PTR (l, l_info[DT_JMPREL]) ++ + reloc_offset (pltgot, reloc_arg)); + const ElfW(Sym) *refsym = &symtab[ELFW(R_SYM) (reloc->r_info)]; + const ElfW(Sym) *defsym = refsym; + lookup_t result; +@@ -485,11 +488,14 @@ _dl_call_pltexit (struct link_map *l, ElfW(Word) reloc_arg, + const void *inregs, void *outregs) + { + #ifdef SHARED ++ const uintptr_t pltgot = (uintptr_t) D_PTR (l, l_info[DT_PLTGOT]); ++ + /* This is the address in the array where we store the result of previous + relocations. */ + // XXX Maybe the bound information must be stored on the stack since + // XXX with bind_not a new value could have been stored in the meantime. +- struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index]; ++ struct reloc_result *reloc_result = ++ &l->l_reloc_result[reloc_index (pltgot, reloc_arg, sizeof (PLTREL))]; + ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, + l_info[DT_SYMTAB]) + + reloc_result->boundndx); +diff --git a/elf/dl-runtime.h b/elf/dl-runtime.h +new file mode 100644 +index 0000000000000000..78f1da77fb4ed905 +--- /dev/null ++++ b/elf/dl-runtime.h +@@ -0,0 +1,30 @@ ++/* Helpers for On-demand PLT fixup for shared objects. Generic version. ++ 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, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++static inline uintptr_t ++reloc_offset (uintptr_t plt0, uintptr_t pltn) ++{ ++ return pltn; ++} ++ ++static inline uintptr_t ++reloc_index (uintptr_t plt0, uintptr_t pltn, size_t size) ++{ ++ return pltn / size; ++} +diff --git a/sysdeps/hppa/dl-runtime.c b/sysdeps/hppa/dl-runtime.c +index 885a3f1837cbc56d..2d061b150f0602c1 100644 +--- a/sysdeps/hppa/dl-runtime.c ++++ b/sysdeps/hppa/dl-runtime.c +@@ -17,10 +17,6 @@ + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +-/* Clear PA_GP_RELOC bit in relocation offset. */ +-#define reloc_offset (reloc_arg & ~PA_GP_RELOC) +-#define reloc_index (reloc_arg & ~PA_GP_RELOC) / sizeof (PLTREL) +- + #include + + /* The caller has encountered a partially relocated function descriptor. +diff --git a/sysdeps/hppa/dl-runtime.h b/sysdeps/hppa/dl-runtime.h +new file mode 100644 +index 0000000000000000..6983aa0ae9b4296c +--- /dev/null ++++ b/sysdeps/hppa/dl-runtime.h +@@ -0,0 +1,31 @@ ++/* Helpers for On-demand PLT fixup for shared objects. HPAA version. ++ 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, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++/* Clear PA_GP_RELOC bit in relocation offset. */ ++static inline uintptr_t ++reloc_offset (uintptr_t plt0, uintptr_t pltn) ++{ ++ return pltn & ~PA_GP_RELOC; ++} ++ ++static inline uintptr_t ++reloc_index (uintptr_t plt0, uintptr_t pltn, size_t size) ++{ ++ return (pltn & ~PA_GP_RELOC )/ size; ++} +diff --git a/sysdeps/x86_64/dl-runtime.c b/sysdeps/x86_64/dl-runtime.c +deleted file mode 100644 +index b625d1e88257b018..0000000000000000 +--- a/sysdeps/x86_64/dl-runtime.c ++++ /dev/null +@@ -1,9 +0,0 @@ +-/* The ABI calls for the PLT stubs to pass the index of the relocation +- and not its offset. In _dl_profile_fixup and _dl_call_pltexit we +- also use the index. Therefore it is wasteful to compute the offset +- in the trampoline just to reverse the operation immediately +- afterwards. */ +-#define reloc_offset reloc_arg * sizeof (PLTREL) +-#define reloc_index reloc_arg +- +-#include +diff --git a/sysdeps/x86_64/dl-runtime.h b/sysdeps/x86_64/dl-runtime.h +new file mode 100644 +index 0000000000000000..3fa61d7a4697cf3f +--- /dev/null ++++ b/sysdeps/x86_64/dl-runtime.h +@@ -0,0 +1,35 @@ ++/* Helpers for On-demand PLT fixup for shared objects. x86_64 version. ++ 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, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++/* The ABI calls for the PLT stubs to pass the index of the relocation ++ and not its offset. In _dl_profile_fixup and _dl_call_pltexit we ++ also use the index. Therefore it is wasteful to compute the offset ++ in the trampoline just to reverse the operation immediately ++ afterwards. */ ++static inline uintptr_t ++reloc_offset (uintptr_t plt0, uintptr_t pltn) ++{ ++ return pltn * sizeof (ElfW(Rela)); ++} ++ ++static inline uintptr_t ++reloc_index (uintptr_t plt0, uintptr_t pltn, size_t size) ++{ ++ return pltn; ++} diff --git a/SOURCES/glibc-rh2047981-30.patch b/SOURCES/glibc-rh2047981-30.patch new file mode 100644 index 0000000..d52225f --- /dev/null +++ b/SOURCES/glibc-rh2047981-30.patch @@ -0,0 +1,520 @@ +commit 7de01e60c200c431d3469deb784da8fd4508fc15 +Author: Florian Weimer +Date: Fri Jan 14 20:16:05 2022 +0100 + + elf/Makefile: Reflow and sort most variable assignments + + Reviewed-by: H.J. Lu + +Conflicts: + elf/Makefile + Complete rewrite of reflow. + +diff --git a/elf/Makefile b/elf/Makefile +index 53faca4585220048..954cd08c199f5037 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -21,20 +21,60 @@ subdir := elf + + include ../Makeconfig + +-headers = elf.h bits/elfclass.h link.h bits/link.h bits/link_lavcurrent.h +-routines = $(all-dl-routines) dl-support dl-iteratephdr \ +- dl-addr dl-addr-obj enbl-secure dl-profstub \ +- dl-origin dl-libc dl-sym dl-sysdep dl-error \ +- dl-reloc-static-pie libc_early_init ++headers = \ ++ bits/elfclass.h \ ++ bits/link.h \ ++ bits/link_lavcurrent.h \ ++ elf.h \ ++ link.h \ ++ # headers ++ ++routines = \ ++ $(all-dl-routines) \ ++ dl-addr \ ++ dl-addr-obj \ ++ dl-error \ ++ dl-iteratephdr \ ++ dl-libc \ ++ dl-origin \ ++ dl-profstub \ ++ dl-reloc-static-pie \ ++ dl-support \ ++ dl-sym \ ++ dl-sysdep \ ++ enbl-secure \ ++ libc_early_init \ ++ # routines + + # The core dynamic linking functions are in libc for the static and + # profiled libraries. +-dl-routines = $(addprefix dl-,load lookup object reloc deps \ +- runtime init fini debug misc \ +- version profile tls origin scope \ +- execstack open close trampoline \ +- exception sort-maps lookup-direct \ +- call-libc-early-init write) ++dl-routines = \ ++ dl-call-libc-early-init \ ++ dl-close \ ++ dl-debug \ ++ dl-deps \ ++ dl-exception \ ++ dl-execstack \ ++ dl-fini \ ++ dl-init \ ++ dl-load \ ++ dl-lookup \ ++ dl-lookup-direct \ ++ dl-misc \ ++ dl-object \ ++ dl-open \ ++ dl-origin \ ++ dl-profile \ ++ dl-reloc \ ++ dl-runtime \ ++ dl-scope \ ++ dl-sort-maps \ ++ dl-tls \ ++ dl-trampoline \ ++ dl-version \ ++ dl-write \ ++ # dl-routines ++ + ifeq (yes,$(use-ldconfig)) + dl-routines += dl-cache + endif +@@ -57,15 +97,36 @@ endif + + all-dl-routines = $(dl-routines) $(sysdep-dl-routines) + # But they are absent from the shared libc, because that code is in ld.so. +-elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ +- dl-sysdep dl-exception dl-reloc-static-pie ++elide-routines.os = \ ++ $(all-dl-routines) \ ++ dl-exception \ ++ dl-origin \ ++ dl-reloc-static-pie \ ++ dl-support \ ++ dl-sysdep \ ++ enbl-secure \ ++ # elide-routines.os + + # ld.so uses those routines, plus some special stuff for being the program + # interpreter and operating independent of libc. +-rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \ +- dl-error-minimal dl-conflict dl-hwcaps dl-hwcaps_split dl-hwcaps-subdirs \ +- dl-usage dl-diagnostics dl-diagnostics-kernel dl-diagnostics-cpu \ +- dl-audit ++rtld-routines = \ ++ $(all-dl-routines) \ ++ dl-audit \ ++ dl-conflict \ ++ dl-diagnostics \ ++ dl-diagnostics-cpu \ ++ dl-diagnostics-kernel \ ++ dl-environ \ ++ dl-error-minimal \ ++ dl-hwcaps \ ++ dl-hwcaps-subdirs \ ++ dl-hwcaps_split \ ++ dl-minimal \ ++ dl-sysdep \ ++ dl-usage \ ++ rtld \ ++ # rtld-routines ++ + all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines) + + CFLAGS-dl-runtime.c += -fexceptions -fasynchronous-unwind-tables +@@ -98,8 +159,18 @@ ld-map = $(common-objpfx)ld.map + endif + + ifeq (yes,$(build-shared)) +-extra-objs = $(all-rtld-routines:%=%.os) soinit.os sofini.os interp.os +-generated += librtld.os dl-allobjs.os ld.so ldd ++extra-objs = \ ++ $(all-rtld-routines:%=%.os) \ ++ sofini.os \ ++ soinit.os \ ++ interp.os \ ++ # extra-objs ++generated += \ ++ dl-allobjs.os \ ++ ldd \ ++ ld.so \ ++ librtld.os \ ++ # generated + install-others = $(inst_rtlddir)/$(rtld-installed-name) $(inst_bindir)/ld.so + install-bin-script = ldd + endif +@@ -117,8 +188,15 @@ others-static += ldconfig + others += ldconfig + install-rootsbin += ldconfig + +-ldconfig-modules := cache readlib xmalloc xstrdup chroot_canon static-stubs \ +- stringtable ++ldconfig-modules := \ ++ cache \ ++ chroot_canon \ ++ readlib \ ++ static-stubs \ ++ stringtable \ ++ xmalloc \ ++ xstrdup \ ++ # ldconfig-modules + extra-objs += $(ldconfig-modules:=.o) + others-extras = $(ldconfig-modules) + endif +@@ -153,20 +231,34 @@ $(inst_auditdir)/sotruss-lib.so: $(objpfx)sotruss-lib.so $(+force) + $(do-install-program) + endif + +-tests-static-normal := tst-leaks1-static tst-array1-static tst-array5-static \ +- tst-dl-iter-static \ +- tst-tlsalign-static tst-tlsalign-extern-static \ +- tst-linkall-static tst-env-setuid tst-env-setuid-tunables \ +- tst-dst-static +-tests-static-internal := tst-tls1-static tst-tls2-static \ +- tst-ptrguard1-static tst-stackguard1-static \ +- tst-tls1-static-non-pie tst-libc_dlvsym-static ++tests-static-normal := \ ++ tst-array1-static \ ++ tst-array5-static \ ++ tst-dl-iter-static \ ++ tst-dst-static \ ++ tst-env-setuid \ ++ tst-env-setuid-tunables \ ++ tst-leaks1-static \ ++ tst-linkall-static \ ++ tst-tlsalign-extern-static \ ++ tst-tlsalign-static \ ++ # tests-static-normal ++ ++tests-static-internal := \ ++ tst-libc_dlvsym-static \ ++ tst-ptrguard1-static \ ++ tst-stackguard1-static \ ++ tst-tls1-static \ ++ tst-tls1-static-non-pie \ ++ tst-tls2-static \ ++ # tests-static-internal + + CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o + tst-tls1-static-non-pie-no-pie = yes + + tests-container = \ +- tst-ldconfig-bad-aux-cache ++ tst-ldconfig-bad-aux-cache \ ++ # tests-container + + ifeq (no,$(build-hardcoded-path-in-tests)) + # This is an ld.so.cache test, and RPATH/RUNPATH in the executable +@@ -174,14 +266,31 @@ ifeq (no,$(build-hardcoded-path-in-tests)) + tests-container += tst-glibc-hwcaps-prepend-cache + endif + +-tests := tst-tls9 tst-leaks1 \ +- tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \ +- tst-auxv tst-stringtable +-tests-internal := tst-tls1 tst-tls2 $(tests-static-internal) ++tests := \ ++ tst-array1 \ ++ tst-array2 \ ++ tst-array3 \ ++ tst-array4 \ ++ tst-array5 \ ++ tst-auxv \ ++ tst-leaks1 \ ++ tst-stringtable \ ++ tst-tls9 \ ++ # tests ++ ++tests-internal := \ ++ $(tests-static-internal) \ ++ tst-tls1 \ ++ tst-tls2 \ ++ # tests-internal ++ + tests-static := $(tests-static-normal) $(tests-static-internal) + + ifeq (yes,$(build-shared)) +-tests-static += tst-tls9-static ++tests-static += \ ++ tst-tls9-static \ ++ # tests-static ++ + tst-tls9-static-ENV = \ + LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn + +@@ -302,37 +411,71 @@ tests += \ + unload6 \ + unload7 \ + unload8 \ +-# reldep9 ++ # tests + tests-cxx = \ + tst-dlopen-nodelete-reloc \ + tst-nodelete \ + tst-unique3 \ + tst-unique4 \ +-# tests-cxx ++ # tests-cxx + + tests += $(if $(CXX),$(tests-cxx)) +-tests-internal += loadtest unload unload2 circleload1 \ +- neededtest neededtest2 neededtest3 neededtest4 \ +- tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \ +- tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \ +- tst-create_format1 tst-tls-surplus tst-dl-hwcaps_split \ +- tst-audit19a +-tests-container += tst-pldd tst-preload-pthread-libc ++ ++tests-internal += \ ++ circleload1 \ ++ loadtest \ ++ neededtest \ ++ neededtest2 \ ++ neededtest3 \ ++ neededtest4 \ ++ tst-audit19a \ ++ tst-create_format1 \ ++ tst-dl-hwcaps_split \ ++ tst-dlmopen2 \ ++ tst-libc_dlvsym \ ++ tst-ptrguard1 \ ++ tst-stackguard1 \ ++ tst-tls-surplus \ ++ tst-tls3 \ ++ tst-tls6 \ ++ tst-tls7 \ ++ tst-tls8 \ ++ unload \ ++ unload2 \ ++ # tests-internal ++ ++tests-container += \ ++ tst-pldd \ ++ tst-preload-pthread-libc ++ # tests-container ++ + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout + tst-dlopen-aout-no-pie = yes + endif +-test-srcs = tst-pathopt ++test-srcs = \ ++ tst-pathopt ++ # tests-srcs ++ + selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null) ++ + ifneq ($(selinux-enabled),1) +-tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog ++tests-execstack-yes = \ ++ tst-execstack \ ++ tst-execstack-needed \ ++ tst-execstack-prog \ ++ # tests-execstack-yes + endif + endif + tests += $(tests-execstack-$(have-z-execstack)) + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-leaks1-mem.out \ +- $(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \ +- $(objpfx)tst-ldconfig-X.out $(objpfx)tst-rtld-help.out ++tests-special += \ ++ $(objpfx)noload-mem.out \ ++ $(objpfx)tst-ldconfig-X.out \ ++ $(objpfx)tst-leaks1-mem.out \ ++ $(objpfx)tst-leaks1-static-mem.out \ ++ $(objpfx)tst-rtld-help.out \ ++ # tests-special + endif + tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + tlsmod18a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 +@@ -349,9 +492,16 @@ tst-tls-many-dynamic-modules-dep = \ + tst-tls-many-dynamic-modules-dep-bad-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + tst-tls-many-dynamic-modules-dep-bad = \ + $(foreach n,$(tst-tls-many-dynamic-modules-dep-bad-suffixes),tst-tls-manydynamic$(n)mod-dep-bad) +-extra-test-objs += $(tlsmod17a-modules:=.os) $(tlsmod18a-modules:=.os) \ +- tst-tlsalign-vars.o +-test-extras += tst-tlsmod17a tst-tlsmod18a tst-tlsalign-vars ++extra-test-objs += \ ++ $(tlsmod17a-modules:=.os) \ ++ $(tlsmod18a-modules:=.os) \ ++ tst-tlsalign-vars.o \ ++ # extra-test-objs ++test-extras += \ ++ tst-tlsalign-vars \ ++ tst-tlsmod17a \ ++ tst-tlsmod18a \ ++ # test-extras + modules-names = \ + circlemod1 \ + circlemod1a \ +@@ -607,17 +757,17 @@ modules-names-cxx = \ + tst-unique3lib \ + tst-unique3lib2 \ + tst-unique4lib \ +-# modules-names-cxx ++ # modules-names-cxx + + modules-names += \ + $(if $(CXX),$(modules-names-cxx)) \ + $(modules-execstack-$(have-z-execstack)) \ ++ $(tlsmod17a-modules) \ ++ $(tlsmod18a-modules) \ + $(tst-tls-many-dynamic-modules) \ + $(tst-tls-many-dynamic-modules-dep) \ + $(tst-tls-many-dynamic-modules-dep-bad) \ +- $(tlsmod17a-modules) \ +- $(tlsmod18a-modules) \ +-# modules-names ++ # modules-names + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -680,54 +830,103 @@ modules-names-nobuild := filtmod1 + tests += $(tests-static) + + ifneq (no,$(multi-arch)) +-tests-ifuncstatic := ifuncmain1static ifuncmain1picstatic \ +- ifuncmain2static ifuncmain2picstatic \ +- ifuncmain4static ifuncmain4picstatic \ +- ifuncmain5static ifuncmain5picstatic \ +- ifuncmain7static ifuncmain7picstatic ++tests-ifuncstatic := \ ++ ifuncmain1static \ ++ ifuncmain1picstatic \ ++ ifuncmain2static \ ++ ifuncmain2picstatic \ ++ ifuncmain4static \ ++ ifuncmain4picstatic \ ++ ifuncmain5static \ ++ ifuncmain5picstatic \ ++ ifuncmain7static \ ++ ifuncmain7picstatic \ ++ # tests-ifuncstatic + tests-static += $(tests-ifuncstatic) + tests-internal += $(tests-ifuncstatic) + ifeq (yes,$(build-shared)) + tests-internal += \ +- ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \ +- ifuncmain1staticpic \ +- ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \ +- ifuncmain5 ifuncmain5pic ifuncmain5staticpic \ +- ifuncmain7 ifuncmain7pic +-ifunc-test-modules = ifuncdep1 ifuncdep1pic ifuncdep2 ifuncdep2pic \ +- ifuncdep5 ifuncdep5pic ++ ifuncmain1 \ ++ ifuncmain1pic \ ++ ifuncmain1staticpic \ ++ ifuncmain1vis \ ++ ifuncmain1vispic \ ++ ifuncmain2 \ ++ ifuncmain2pic \ ++ ifuncmain3 \ ++ ifuncmain4 \ ++ ifuncmain5 \ ++ ifuncmain5pic \ ++ ifuncmain5staticpic \ ++ ifuncmain7 \ ++ ifuncmain7pic \ ++ # tests-internal ++ifunc-test-modules = \ ++ ifuncdep1 \ ++ ifuncdep1pic \ ++ ifuncdep2 \ ++ ifuncdep2pic \ ++ ifuncdep5 \ ++ ifuncdep5pic \ ++ # ifunc-test-modules + extra-test-objs += $(ifunc-test-modules:=.o) + test-internal-extras += $(ifunc-test-modules) + ifeq (yes,$(have-fpie)) +-ifunc-pie-tests = ifuncmain1pie ifuncmain1vispie ifuncmain1staticpie \ +- ifuncmain5pie ifuncmain6pie ifuncmain7pie ++ifunc-pie-tests = \ ++ ifuncmain1pie \ ++ ifuncmain1staticpie \ ++ ifuncmain1vispie \ ++ ifuncmain5pie \ ++ ifuncmain6pie \ ++ ifuncmain7pie \ ++ # ifunc-pie-tests + tests-internal += $(ifunc-pie-tests) + tests-pie += $(ifunc-pie-tests) + endif +-modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6 ++modules-names += \ ++ ifuncmod1 \ ++ ifuncmod3 \ ++ ifuncmod5 \ ++ ifuncmod6 \ ++ # modules-names + endif + endif + + ifeq (yes,$(build-shared)) + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)tst-pathopt.out $(objpfx)tst-rtld-load-self.out \ +- $(objpfx)tst-rtld-preload.out $(objpfx)argv0test.out \ +- $(objpfx)tst-rtld-help.out ++tests-special += \ ++ $(objpfx)argv0test.out \ ++ $(objpfx)tst-pathopt.out \ ++ $(objpfx)tst-rtld-help.out \ ++ $(objpfx)tst-rtld-load-self.out \ ++ $(objpfx)tst-rtld-preload.out \ ++ # tests-special + endif +-tests-special += $(objpfx)check-textrel.out $(objpfx)check-execstack.out \ +- $(objpfx)check-wx-segment.out \ +- $(objpfx)check-localplt.out $(objpfx)check-initfini.out ++tests-special += \ ++ $(objpfx)check-execstack.out \ ++ $(objpfx)check-initfini.out \ ++ $(objpfx)check-localplt.out \ ++ $(objpfx)check-textrel.out \ ++ $(objpfx)check-wx-segment.out \ ++ # tests-special + endif + + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)order-cmp.out $(objpfx)tst-array1-cmp.out \ +- $(objpfx)tst-array1-static-cmp.out \ +- $(objpfx)tst-array2-cmp.out $(objpfx)tst-array3-cmp.out \ +- $(objpfx)tst-array4-cmp.out $(objpfx)tst-array5-cmp.out \ +- $(objpfx)tst-array5-static-cmp.out $(objpfx)order2-cmp.out \ +- $(objpfx)tst-initorder-cmp.out \ +- $(objpfx)tst-initorder2-cmp.out $(objpfx)tst-unused-dep.out \ +- $(objpfx)tst-unused-dep-cmp.out ++tests-special += \ ++ $(objpfx)order-cmp.out \ ++ $(objpfx)order2-cmp.out \ ++ $(objpfx)tst-array1-cmp.out \ ++ $(objpfx)tst-array1-static-cmp.out \ ++ $(objpfx)tst-array2-cmp.out \ ++ $(objpfx)tst-array3-cmp.out \ ++ $(objpfx)tst-array4-cmp.out \ ++ $(objpfx)tst-array5-cmp.out \ ++ $(objpfx)tst-array5-static-cmp.out \ ++ $(objpfx)tst-initorder-cmp.out \ ++ $(objpfx)tst-initorder2-cmp.out \ ++ $(objpfx)tst-unused-dep-cmp.out \ ++ $(objpfx)tst-unused-dep.out \ ++ # tests-special + endif + + check-abi: $(objpfx)check-abi-ld.out +@@ -807,6 +1006,7 @@ rtld-stubbed-symbols = \ + free \ + malloc \ + realloc \ ++ # rtld-stubbed-symbols + + # The GCC arguments that implement $(rtld-stubbed-symbols). + rtld-stubbed-symbols-args = \ diff --git a/SOURCES/glibc-rh2047981-31.patch b/SOURCES/glibc-rh2047981-31.patch new file mode 100644 index 0000000..48de026 --- /dev/null +++ b/SOURCES/glibc-rh2047981-31.patch @@ -0,0 +1,440 @@ +Added $(objpfx)tst-audit23: $(libdl) to elf/Makefile since +we still need $(libdl) in RHEL8. + +commit 5fa11a2bc94c912c3b25860065086902674537ba +Author: Adhemerval Zanella +Date: Mon Jan 24 10:46:15 2022 -0300 + + elf: Add la_activity during application exit + + la_activity is not called during application exit, even though + la_objclose is. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index 954cd08c199f5037..e4955c9f575f9015 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -345,6 +345,7 @@ tests += \ + tst-audit2 \ + tst-audit20 \ + tst-audit22 \ ++ tst-audit23 \ + tst-audit8 \ + tst-audit9 \ + tst-auditmany \ +@@ -608,6 +609,7 @@ modules-names = \ + tst-audit13mod1 \ + tst-audit18mod \ + tst-audit19bmod \ ++ tst-audit23mod \ + tst-auditlogmod-1 \ + tst-auditlogmod-2 \ + tst-auditlogmod-3 \ +@@ -630,6 +632,7 @@ modules-names = \ + tst-auditmod19b \ + tst-auditmod20 \ + tst-auditmod22 \ ++ tst-auditmod23 \ + tst-big-note-lib \ + tst-deep1mod1 \ + tst-deep1mod2 \ +@@ -2041,6 +2044,11 @@ $(objpfx)tst-auditmod20.so: $(libdl) + $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so + tst-audit22-ARGS = -- $(host-test-program-cmd) + ++$(objpfx)tst-audit23: $(libdl) ++$(objpfx)tst-audit23.out: $(objpfx)tst-auditmod23.so \ ++ $(objpfx)tst-audit23mod.so ++tst-audit23-ARGS = -- $(host-test-program-cmd) ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index e102d93647cb8c47..eea9d8aad736a99e 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -63,6 +63,10 @@ _dl_fini (void) + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + else + { ++#ifdef SHARED ++ _dl_audit_activity_nsid (ns, LA_ACT_DELETE); ++#endif ++ + /* Now we can allocate an array to hold all the pointers and + copy the pointers in. */ + struct link_map *maps[nloaded]; +@@ -153,6 +157,10 @@ _dl_fini (void) + /* Correct the previous increment. */ + --l->l_direct_opencount; + } ++ ++#ifdef SHARED ++ _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT); ++#endif + } + } + +diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c +new file mode 100644 +index 0000000000000000..4904cf1340a97ee1 +--- /dev/null ++++ b/elf/tst-audit23.c +@@ -0,0 +1,239 @@ ++/* Check for expected la_objopen and la_objeclose for all objects. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++static int ++handle_restart (void) ++{ ++ xdlopen ("tst-audit23mod.so", RTLD_NOW); ++ xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); ++ ++ return 0; ++} ++ ++static inline bool ++startswith (const char *str, const char *pre) ++{ ++ size_t lenpre = strlen (pre); ++ size_t lenstr = strlen (str); ++ return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0; ++} ++ ++static inline bool ++is_vdso (const char *str) ++{ ++ return startswith (str, "linux-gate") ++ || startswith (str, "linux-vdso"); ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ - One or four parameters left if called initially: ++ + path to ld.so optional ++ + "--library-path" optional ++ + the library path optional ++ + the application name */ ++ if (restart) ++ return handle_restart (); ++ ++ char *spargv[9]; ++ TEST_VERIFY_EXIT (((argc - 1) + 3) < array_length (spargv)); ++ int i = 0; ++ for (; i < argc - 1; i++) ++ spargv[i] = argv[i + 1]; ++ spargv[i++] = (char *) "--direct"; ++ spargv[i++] = (char *) "--restart"; ++ spargv[i] = NULL; ++ ++ setenv ("LD_AUDIT", "tst-auditmod23.so", 0); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr); ++ ++ /* The expected la_objopen/la_objclose: ++ 1. executable ++ 2. loader ++ 3. libc.so ++ 4. tst-audit23mod.so ++ 5. libc.so (LM_ID_NEWLM). ++ 6. vdso (optional and ignored). */ ++ enum { max_objs = 6 }; ++ struct la_obj_t ++ { ++ char *lname; ++ uintptr_t laddr; ++ Lmid_t lmid; ++ bool closed; ++ } objs[max_objs] = { [0 ... max_objs-1] = { .closed = false } }; ++ size_t nobjs = 0; ++ ++ /* The expected namespaces are one for the audit module, one for the ++ application, and another for the dlmopen on handle_restart. */ ++ enum { max_ns = 3 }; ++ uintptr_t acts[max_ns] = { 0 }; ++ size_t nacts = 0; ++ int last_act = -1; ++ uintptr_t last_act_cookie = -1; ++ bool seen_first_objclose = false; ++ ++ FILE *out = fmemopen (result.err.buffer, result.err.length, "r"); ++ TEST_VERIFY (out != NULL); ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ while (xgetline (&buffer, &buffer_length, out)) ++ { ++ if (startswith (buffer, "la_activity: ")) ++ { ++ uintptr_t cookie; ++ int this_act; ++ int r = sscanf (buffer, "la_activity: %d %"SCNxPTR"", &this_act, ++ &cookie); ++ TEST_COMPARE (r, 2); ++ ++ /* The cookie identifies the object at the head of the link map, ++ so we only add a new namespace if it changes from the previous ++ one. This works since dlmopen is the last in the test body. */ ++ if (cookie != last_act_cookie && last_act_cookie != -1) ++ TEST_COMPARE (last_act, LA_ACT_CONSISTENT); ++ ++ if (this_act == LA_ACT_ADD && acts[nacts] != cookie) ++ { ++ acts[nacts++] = cookie; ++ last_act_cookie = cookie; ++ } ++ /* The LA_ACT_DELETE is called in the reverse order of LA_ACT_ADD ++ at program termination (if the tests adds a dlclose or a library ++ with extra dependencies this will need to be adapted). */ ++ else if (this_act == LA_ACT_DELETE) ++ { ++ last_act_cookie = acts[--nacts]; ++ TEST_COMPARE (acts[nacts], cookie); ++ acts[nacts] = 0; ++ } ++ else if (this_act == LA_ACT_CONSISTENT) ++ { ++ TEST_COMPARE (cookie, last_act_cookie); ++ ++ /* LA_ACT_DELETE must always be followed by an la_objclose. */ ++ if (last_act == LA_ACT_DELETE) ++ TEST_COMPARE (seen_first_objclose, true); ++ else ++ TEST_COMPARE (last_act, LA_ACT_ADD); ++ } ++ ++ last_act = this_act; ++ seen_first_objclose = false; ++ } ++ else if (startswith (buffer, "la_objopen: ")) ++ { ++ char *lname; ++ uintptr_t laddr; ++ Lmid_t lmid; ++ uintptr_t cookie; ++ int r = sscanf (buffer, "la_objopen: %"SCNxPTR" %ms %"SCNxPTR" %ld", ++ &cookie, &lname, &laddr, &lmid); ++ TEST_COMPARE (r, 4); ++ ++ /* la_objclose is not triggered by vDSO because glibc does not ++ unload it. */ ++ if (is_vdso (lname)) ++ continue; ++ if (nobjs == max_objs) ++ FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld", ++ lname, laddr, lmid); ++ objs[nobjs].lname = lname; ++ objs[nobjs].laddr = laddr; ++ objs[nobjs].lmid = lmid; ++ objs[nobjs].closed = false; ++ nobjs++; ++ ++ /* This indirectly checks that la_objopen always comes before ++ la_objclose btween la_activity calls. */ ++ seen_first_objclose = false; ++ } ++ else if (startswith (buffer, "la_objclose: ")) ++ { ++ char *lname; ++ uintptr_t laddr; ++ Lmid_t lmid; ++ uintptr_t cookie; ++ int r = sscanf (buffer, "la_objclose: %"SCNxPTR" %ms %"SCNxPTR" %ld", ++ &cookie, &lname, &laddr, &lmid); ++ TEST_COMPARE (r, 4); ++ ++ for (size_t i = 0; i < nobjs; i++) ++ { ++ if (strcmp (lname, objs[i].lname) == 0 && lmid == objs[i].lmid) ++ { ++ TEST_COMPARE (objs[i].closed, false); ++ objs[i].closed = true; ++ break; ++ } ++ } ++ ++ /* la_objclose should be called after la_activity(LA_ACT_DELETE) for ++ the closed object's namespace. */ ++ TEST_COMPARE (last_act, LA_ACT_DELETE); ++ if (!seen_first_objclose) ++ { ++ TEST_COMPARE (last_act_cookie, cookie); ++ seen_first_objclose = true; ++ } ++ } ++ } ++ ++ for (size_t i = 0; i < nobjs; i++) ++ { ++ TEST_COMPARE (objs[i].closed, true); ++ free (objs[i].lname); ++ } ++ ++ /* la_activity(LA_ACT_CONSISTENT) should be the last callback received. ++ Since only one link map may be not-CONSISTENT at a time, this also ++ ensures la_activity(LA_ACT_CONSISTENT) is the last callback received ++ for every namespace. */ ++ TEST_COMPARE (last_act, LA_ACT_CONSISTENT); ++ ++ free (buffer); ++ xfclose (out); ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-audit23mod.c b/elf/tst-audit23mod.c +new file mode 100644 +index 0000000000000000..30315687037d25e8 +--- /dev/null ++++ b/elf/tst-audit23mod.c +@@ -0,0 +1,23 @@ ++/* Extra module for tst-audit23 ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++int ++foo (void) ++{ ++ return 0; ++} +diff --git a/elf/tst-auditmod23.c b/elf/tst-auditmod23.c +new file mode 100644 +index 0000000000000000..d7c60d7a5cbc4f8a +--- /dev/null ++++ b/elf/tst-auditmod23.c +@@ -0,0 +1,74 @@ ++/* Audit module loaded by tst-audit23. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++struct map_desc_t ++{ ++ char *lname; ++ uintptr_t laddr; ++ Lmid_t lmid; ++}; ++ ++void ++la_activity (uintptr_t *cookie, unsigned int flag) ++{ ++ fprintf (stderr, "%s: %d %"PRIxPTR"\n", __func__, flag, (uintptr_t) cookie); ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *l_name = map->l_name[0] == '\0' ? "mainapp" : map->l_name; ++ fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__, ++ (uintptr_t) cookie, l_name, map->l_addr, lmid); ++ ++ struct map_desc_t *map_desc = malloc (sizeof (struct map_desc_t)); ++ if (map_desc == NULL) ++ abort (); ++ ++ map_desc->lname = strdup (l_name); ++ map_desc->laddr = map->l_addr; ++ map_desc->lmid = lmid; ++ ++ *cookie = (uintptr_t) map_desc; ++ ++ return 0; ++} ++ ++unsigned int ++la_objclose (uintptr_t *cookie) ++{ ++ struct map_desc_t *map_desc = (struct map_desc_t *) *cookie; ++ fprintf (stderr, "%s: %"PRIxPTR" %s %"PRIxPTR" %ld\n", __func__, ++ (uintptr_t) cookie, map_desc->lname, map_desc->laddr, ++ map_desc->lmid); ++ ++ return 0; ++} diff --git a/SOURCES/glibc-rh2047981-32.patch b/SOURCES/glibc-rh2047981-32.patch new file mode 100644 index 0000000..2706fe8 --- /dev/null +++ b/SOURCES/glibc-rh2047981-32.patch @@ -0,0 +1,298 @@ +commit 254d3d5aef2fd8430c469e1938209ac100ebf132 +Author: Adhemerval Zanella +Date: Mon Jan 24 10:46:16 2022 -0300 + + elf: Fix initial-exec TLS access on audit modules (BZ #28096) + + For audit modules and dependencies with initial-exec TLS, we can not + set the initial TLS image on default loader initialization because it + would already be set by the audit setup. However, subsequent thread + creation would need to follow the default behaviour. + + This patch fixes it by setting l_auditing link_map field not only + for the audit modules, but also for all its dependencies. This is + used on _dl_allocate_tls_init to avoid the static TLS initialization + at load time. + + Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu. + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +diff --git a/elf/Makefile b/elf/Makefile +index e4955c9f575f9015..3f5f72257a5fbea4 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -344,6 +344,7 @@ tests += \ + tst-audit19b \ + tst-audit2 \ + tst-audit20 \ ++ tst-audit21 \ + tst-audit22 \ + tst-audit23 \ + tst-audit8 \ +@@ -631,6 +632,8 @@ modules-names = \ + tst-auditmod19a \ + tst-auditmod19b \ + tst-auditmod20 \ ++ tst-auditmod21a \ ++ tst-auditmod21b \ + tst-auditmod22 \ + tst-auditmod23 \ + tst-big-note-lib \ +@@ -2041,6 +2044,11 @@ $(objpfx)tst-audit20.out: $(objpfx)tst-auditmod20.so + tst-audit20-ENV = LD_AUDIT=$(objpfx)tst-auditmod20.so + $(objpfx)tst-auditmod20.so: $(libdl) + ++$(objpfx)tst-audit21: $(shared-thread-library) ++$(objpfx)tst-audit21.out: $(objpfx)tst-auditmod21a.so ++$(objpfx)tst-auditmod21a.so: $(objpfx)tst-auditmod21b.so ++tst-audit21-ENV = LD_AUDIT=$(objpfx)tst-auditmod21a.so ++ + $(objpfx)tst-audit22.out: $(objpfx)tst-auditmod22.so + tst-audit22-ARGS = -- $(host-test-program-cmd) + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 7865fc390c3f3f0a..a918e9a6f585eb72 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -514,8 +514,12 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid) + } + + ++/* Allocate initial TLS. RESULT should be a non-NULL pointer to storage ++ for the TLS space. The DTV may be resized, and so this function may ++ call malloc to allocate that space. The loader's GL(dl_load_tls_lock) ++ is taken when manipulating global TLS-related data in the loader. */ + void * +-_dl_allocate_tls_init (void *result) ++_dl_allocate_tls_init (void *result, bool init_tls) + { + if (result == NULL) + /* The memory allocation failed. */ +@@ -588,7 +592,14 @@ _dl_allocate_tls_init (void *result) + some platforms use in static programs requires it. */ + dtv[map->l_tls_modid].pointer.val = dest; + +- /* Copy the initialization image and clear the BSS part. */ ++ /* Copy the initialization image and clear the BSS part. For ++ audit modules or dependencies with initial-exec TLS, we can not ++ set the initial TLS image on default loader initialization ++ because it would already be set by the audit setup. However, ++ subsequent thread creation would need to follow the default ++ behaviour. */ ++ if (map->l_ns != LM_ID_BASE && !init_tls) ++ continue; + memset (__mempcpy (dest, map->l_tls_initimage, + map->l_tls_initimage_size), '\0', + map->l_tls_blocksize - map->l_tls_initimage_size); +@@ -615,7 +626,7 @@ _dl_allocate_tls (void *mem) + { + return _dl_allocate_tls_init (mem == NULL + ? _dl_allocate_tls_storage () +- : allocate_dtv (mem)); ++ : allocate_dtv (mem), true); + } + rtld_hidden_def (_dl_allocate_tls) + +diff --git a/elf/rtld.c b/elf/rtld.c +index efcbeac6c24c4b7b..caa980dbda3d1a72 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2421,7 +2421,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + into the main thread's TLS area, which we allocated above. + Note: thread-local variables must only be accessed after completing + the next step. */ +- _dl_allocate_tls_init (tcbp); ++ _dl_allocate_tls_init (tcbp, false); + + /* And finally install it for the main thread. */ + if (! tls_init_tp_called) +diff --git a/elf/tst-audit21.c b/elf/tst-audit21.c +new file mode 100644 +index 0000000000000000..3a47ab64d44421ee +--- /dev/null ++++ b/elf/tst-audit21.c +@@ -0,0 +1,42 @@ ++/* Check LD_AUDIT with static TLS. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++static volatile __thread int out __attribute__ ((tls_model ("initial-exec"))); ++ ++static void * ++tf (void *arg) ++{ ++ TEST_COMPARE (out, 0); ++ out = isspace (' '); ++ return NULL; ++} ++ ++int main (int argc, char *argv[]) ++{ ++ TEST_COMPARE (out, 0); ++ out = isspace (' '); ++ ++ pthread_t t = xpthread_create (NULL, tf, NULL); ++ xpthread_join (t); ++ ++ return 0; ++} +diff --git a/elf/tst-auditmod21a.c b/elf/tst-auditmod21a.c +new file mode 100644 +index 0000000000000000..f6d51b5c0531c49d +--- /dev/null ++++ b/elf/tst-auditmod21a.c +@@ -0,0 +1,80 @@ ++/* Check LD_AUDIT with static TLS. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++#define tls_ie __attribute__ ((tls_model ("initial-exec"))) ++ ++__thread int tls_var0 tls_ie; ++__thread int tls_var1 tls_ie = 0x10; ++ ++/* Defined at tst-auditmod21b.so */ ++extern __thread int tls_var2; ++extern __thread int tls_var3; ++ ++static volatile int out; ++ ++static void ++call_libc (void) ++{ ++ /* isspace accesses the initial-exec glibc TLS variables, which are ++ setup in glibc initialization. */ ++ out = isspace (' '); ++} ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ tls_var0 = 0x1; ++ if (tls_var1 != 0x10) ++ abort (); ++ tls_var1 = 0x20; ++ ++ tls_var2 = 0x2; ++ if (tls_var3 != 0x20) ++ abort (); ++ tls_var3 = 0x40; ++ ++ call_libc (); ++ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map* map, Lmid_t lmid, uintptr_t* cookie) ++{ ++ call_libc (); ++ *cookie = (uintptr_t) map; ++ return 0; ++} ++ ++void ++la_activity (uintptr_t* cookie, unsigned int flag) ++{ ++ if (tls_var0 != 0x1 || tls_var1 != 0x20) ++ abort (); ++ call_libc (); ++} ++ ++void ++la_preinit (uintptr_t* cookie) ++{ ++ call_libc (); ++} +diff --git a/elf/tst-auditmod21b.c b/elf/tst-auditmod21b.c +new file mode 100644 +index 0000000000000000..6ba5335b7514c674 +--- /dev/null ++++ b/elf/tst-auditmod21b.c +@@ -0,0 +1,22 @@ ++/* Check LD_AUDIT with static TLS. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define tls_ie __attribute__ ((tls_model ("initial-exec"))) ++ ++__thread int tls_var2 tls_ie; ++__thread int tls_var3 tls_ie = 0x20; +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 5fa45b19987717e1..58170d9da2bf0fa6 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -244,7 +244,7 @@ get_cached_stack (size_t *sizep, void **memp) + memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t)); + + /* Re-initialize the TLS. */ +- _dl_allocate_tls_init (TLS_TPADJ (result)); ++ _dl_allocate_tls_init (TLS_TPADJ (result), true); + + return result; + } +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 29b77b35175c1116..73f4863fd43922b9 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1182,7 +1182,7 @@ extern void _dl_allocate_static_tls (struct link_map *map) attribute_hidden; + /* These are internal entry points to the two halves of _dl_allocate_tls, + only used within rtld.c itself at startup time. */ + extern void *_dl_allocate_tls_storage (void) attribute_hidden; +-extern void *_dl_allocate_tls_init (void *); ++extern void *_dl_allocate_tls_init (void *, bool); + rtld_hidden_proto (_dl_allocate_tls_init) + + /* Deallocate memory allocated with _dl_allocate_tls. */ diff --git a/SOURCES/glibc-rh2047981-33.patch b/SOURCES/glibc-rh2047981-33.patch new file mode 100644 index 0000000..6ce117c --- /dev/null +++ b/SOURCES/glibc-rh2047981-33.patch @@ -0,0 +1,1777 @@ +commit 32612615c58b394c3eb09f020f31310797ad3854 +Author: Adhemerval Zanella +Date: Mon Jan 24 10:46:17 2022 -0300 + + elf: Issue la_symbind for bind-now (BZ #23734) + + The audit symbind callback is not called for binaries built with + -Wl,-z,now or when LD_BIND_NOW=1 is used, nor the PLT tracking callbacks + (plt_enter and plt_exit) since this would change the expected + program semantics (where no PLT is expected) and would have performance + implications (such as for BZ#15533). + + LAV_CURRENT is also bumped to indicate the audit ABI change (where + la_symbind flags are set by the loader to indicate no possible PLT + trace). + + To handle powerpc64 ELFv1 function descriptor, _dl_audit_symbind + requires to know whether bind-now is used so the symbol value is + updated to function text segment instead of the OPD (for lazy binding + this is done by PPC64_LOAD_FUNCPTR on _dl_runtime_resolve). + + Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, + powerpc64-linux-gnu. + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +Conflicts: + elf/Makefile + +diff --git a/bits/link_lavcurrent.h b/bits/link_lavcurrent.h +index 44fbea1e8060997f..c48835d12b512355 100644 +--- a/bits/link_lavcurrent.h ++++ b/bits/link_lavcurrent.h +@@ -22,4 +22,4 @@ + #endif + + /* Version numbers for la_version handshake interface. */ +-#define LAV_CURRENT 1 ++#define LAV_CURRENT 2 +diff --git a/elf/Makefile b/elf/Makefile +index 3f5f72257a5fbea4..78147ed2dbcaf4c0 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -347,6 +347,12 @@ tests += \ + tst-audit21 \ + tst-audit22 \ + tst-audit23 \ ++ tst-audit24a \ ++ tst-audit24b \ ++ tst-audit24c \ ++ tst-audit24d \ ++ tst-audit25a \ ++ tst-audit25b \ + tst-audit8 \ + tst-audit9 \ + tst-auditmany \ +@@ -611,6 +617,18 @@ modules-names = \ + tst-audit18mod \ + tst-audit19bmod \ + tst-audit23mod \ ++ tst-audit24amod1 \ ++ tst-audit24amod2 \ ++ tst-audit24bmod1 \ ++ tst-audit24bmod2 \ ++ tst-audit24dmod1 \ ++ tst-audit24dmod2 \ ++ tst-audit24dmod3 \ ++ tst-audit24dmod4 \ ++ tst-audit25mod1 \ ++ tst-audit25mod2 \ ++ tst-audit25mod3 \ ++ tst-audit25mod4 \ + tst-auditlogmod-1 \ + tst-auditlogmod-2 \ + tst-auditlogmod-3 \ +@@ -636,6 +654,11 @@ modules-names = \ + tst-auditmod21b \ + tst-auditmod22 \ + tst-auditmod23 \ ++ tst-auditmod24a \ ++ tst-auditmod24b \ ++ tst-auditmod24c \ ++ tst-auditmod24d \ ++ tst-auditmod25 \ + tst-big-note-lib \ + tst-deep1mod1 \ + tst-deep1mod2 \ +@@ -831,7 +854,8 @@ modules-execstack-yes = tst-execstack-mod + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + + # filtmod1.so has a special rule +-modules-names-nobuild := filtmod1 ++modules-names-nobuild := filtmod1 \ ++ tst-audit24bmod1 tst-audit24bmod2.so + + tests += $(tests-static) + +@@ -2057,6 +2081,69 @@ $(objpfx)tst-audit23.out: $(objpfx)tst-auditmod23.so \ + $(objpfx)tst-audit23mod.so + tst-audit23-ARGS = -- $(host-test-program-cmd) + ++$(objpfx)tst-audit24a.out: $(objpfx)tst-auditmod24a.so ++$(objpfx)tst-audit24a: $(objpfx)tst-audit24amod1.so \ ++ $(objpfx)tst-audit24amod2.so ++tst-audit24a-ENV = LD_AUDIT=$(objpfx)tst-auditmod24a.so ++LDFLAGS-tst-audit24a = -Wl,-z,now ++ ++$(objpfx)tst-audit24b.out: $(objpfx)tst-auditmod24b.so ++$(objpfx)tst-audit24b: $(objpfx)tst-audit24bmod1.so \ ++ $(objpfx)tst-audit24bmod2.so ++$(objpfx)tst-audit24bmod1: $(objpfx)tst-audit24bmod2.so ++# The test checks if a library without .gnu.version correctly calls the ++# audit callbacks. So it uses an explicit link rule to avoid linking ++# against libc.so. ++$(objpfx)tst-audit24bmod1.so: $(objpfx)tst-audit24bmod1.os ++ $(CC) -nostdlib -nostartfiles -shared -o $@.new $(objpfx)tst-audit24bmod1.os \ ++ -Wl,-z,now ++ $(call after-link,$@.new) ++ mv -f $@.new $@ ++CFLAGS-.os += $(call elide-stack-protector,.os,tst-audit24bmod1) ++$(objpfx)tst-audit24bmod2.so: $(objpfx)tst-audit24bmod2.os ++ $(CC) -nostdlib -nostartfiles -shared -o $@.new $(objpfx)tst-audit24bmod2.os ++ $(call after-link,$@.new) ++ mv -f $@.new $@ ++CFLAGS-.os += $(call elide-stack-protector,.os,tst-audit24bmod2) ++tst-audit24b-ENV = LD_AUDIT=$(objpfx)tst-auditmod24b.so ++LDFLAGS-tst-audit24b = -Wl,-z,now ++ ++# Same as tst-audit24a, but tests LD_BIND_NOW ++$(objpfx)tst-audit24c.out: $(objpfx)tst-auditmod24c.so ++$(objpfx)tst-audit24c: $(objpfx)tst-audit24amod1.so \ ++ $(objpfx)tst-audit24amod2.so ++tst-audit24c-ENV = LD_BIND_NOW=1 LD_AUDIT=$(objpfx)tst-auditmod24c.so ++LDFLAGS-tst-audit24b = -Wl,-z,lazy ++ ++$(objpfx)tst-audit24d.out: $(objpfx)tst-auditmod24d.so ++$(objpfx)tst-audit24d: $(objpfx)tst-audit24dmod1.so \ ++ $(objpfx)tst-audit24dmod2.so ++$(objpfx)tst-audit24dmod1.so: $(objpfx)tst-audit24dmod3.so ++LDFLAGS-tst-audit24dmod1.so = -Wl,-z,now ++$(objpfx)tst-audit24dmod2.so: $(objpfx)tst-audit24dmod4.so ++LDFLAGS-tst-audit24dmod2.so = -Wl,-z,lazy ++tst-audit24d-ENV = LD_AUDIT=$(objpfx)tst-auditmod24d.so ++LDFLAGS-tst-audit24d = -Wl,-z,lazy ++ ++$(objpfx)tst-audit25a.out: $(objpfx)tst-auditmod25.so ++$(objpfx)tst-audit25a: $(objpfx)tst-audit25mod1.so \ ++ $(objpfx)tst-audit25mod2.so \ ++ $(objpfx)tst-audit25mod3.so \ ++ $(objpfx)tst-audit25mod4.so ++$(objpfx)tst-audit25mod1.so: $(objpfx)tst-audit25mod3.so ++LDFLAGS-tst-audit25mod1.so = -Wl,-z,now ++$(objpfx)tst-audit25mod2.so: $(objpfx)tst-audit25mod4.so ++LDFLAGS-tst-audit25mod2.so = -Wl,-z,lazy ++tst-audit25a-ARGS = -- $(host-test-program-cmd) ++ ++$(objpfx)tst-audit25b.out: $(objpfx)tst-auditmod25.so ++$(objpfx)tst-audit25b: $(objpfx)tst-audit25mod1.so \ ++ $(objpfx)tst-audit25mod2.so \ ++ $(objpfx)tst-audit25mod3.so \ ++ $(objpfx)tst-audit25mod4.so ++LDFLAGS-tst-audit25b = -Wl,-z,now ++tst-audit25b-ARGS = -- $(host-test-program-cmd) ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index 152712b12fed6de2..72a50717ef60a357 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -178,16 +178,23 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value, + lookup_t result) + { +- reloc_result->bound = result; +- /* Compute index of the symbol entry in the symbol table of the DSO with the +- definition. */ +- reloc_result->boundndx = (defsym - (ElfW(Sym) *) D_PTR (result, +- l_info[DT_SYMTAB])); ++ bool for_jmp_slot = reloc_result == NULL; ++ ++ /* Compute index of the symbol entry in the symbol table of the DSO ++ with the definition. */ ++ unsigned int boundndx = defsym - (ElfW(Sym) *) D_PTR (result, ++ l_info[DT_SYMTAB]); ++ if (!for_jmp_slot) ++ { ++ reloc_result->bound = result; ++ reloc_result->boundndx = boundndx; ++ } + + if ((l->l_audit_any_plt | result->l_audit_any_plt) == 0) + { + /* Set all bits since this symbol binding is not interesting. */ +- reloc_result->enterexit = (1u << DL_NNS) - 1; ++ if (!for_jmp_slot) ++ reloc_result->enterexit = (1u << DL_NNS) - 1; + return; + } + +@@ -199,12 +206,13 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + two bits. */ + assert (DL_NNS * 2 <= sizeof (reloc_result->flags) * 8); + assert ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) == 3); +- reloc_result->enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT; ++ uint32_t enterexit = LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT; + + const char *strtab2 = (const void *) D_PTR (result, l_info[DT_STRTAB]); + + unsigned int flags = 0; + struct audit_ifaces *afct = GLRO(dl_audit); ++ uintptr_t new_value = (uintptr_t) sym.st_value; + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) + { + /* XXX Check whether both DSOs must request action or only one */ +@@ -215,37 +223,41 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + { + if (afct->symbind != NULL) + { +- uintptr_t new_value = afct->symbind (&sym, +- reloc_result->boundndx, +- &l_state->cookie, +- &result_state->cookie, +- &flags, +- strtab2 + defsym->st_name); ++ flags |= for_jmp_slot ? LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT ++ : 0; ++ new_value = afct->symbind (&sym, boundndx, ++ &l_state->cookie, ++ &result_state->cookie, &flags, ++ strtab2 + defsym->st_name); + if (new_value != (uintptr_t) sym.st_value) + { + flags |= LA_SYMB_ALTVALUE; +- sym.st_value = new_value; ++ sym.st_value = for_jmp_slot ++ ? DL_FIXUP_BINDNOW_ADDR_VALUE (new_value) : new_value; + } + } + + /* Remember the results for every audit library and store a summary + in the first two bits. */ +- reloc_result->enterexit &= flags & (LA_SYMB_NOPLTENTER +- | LA_SYMB_NOPLTEXIT); +- reloc_result->enterexit |= ((flags & (LA_SYMB_NOPLTENTER +- | LA_SYMB_NOPLTEXIT)) +- << ((cnt + 1) * 2)); ++ enterexit &= flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT); ++ enterexit |= ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) ++ << ((cnt + 1) * 2)); + } + else + /* If the bind flags say this auditor is not interested, set the bits + manually. */ +- reloc_result->enterexit |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) +- << ((cnt + 1) * 2)); ++ enterexit |= ((LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ++ << ((cnt + 1) * 2)); + afct = afct->next; + } + +- reloc_result->flags = flags; +- *value = DL_FIXUP_ADDR_VALUE (sym.st_value); ++ if (!for_jmp_slot) ++ { ++ reloc_result->enterexit = enterexit; ++ reloc_result->flags = flags; ++ } ++ ++ DL_FIXUP_BINDNOW_RELOC (value, new_value, sym.st_value); + } + + void +diff --git a/elf/do-rel.h b/elf/do-rel.h +index 0b04d1a0bf28b9f4..43c80e1c0067d9ca 100644 +--- a/elf/do-rel.h ++++ b/elf/do-rel.h +@@ -16,6 +16,8 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++ + /* This file may be included twice, to define both + `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. */ + +@@ -123,6 +125,10 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[], + + for (; r < end; ++r) + { ++ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff; ++ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)]; ++ void *const r_addr_arg = (void *) (l_addr + r->r_offset); ++ const struct r_found_version *rversion = &map->l_versions[ndx]; + #if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP + if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE) + { +@@ -133,10 +139,19 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[], + } + #endif + +- ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff; +- elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], +- &map->l_versions[ndx], +- (void *) (l_addr + r->r_offset), skip_ifunc); ++ elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, ++ skip_ifunc); ++#if defined SHARED && !defined RTLD_BOOTSTRAP ++ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT ++ && GLRO(dl_naudit) > 0) ++ { ++ struct link_map *sym_map ++ = RESOLVE_MAP (map, scope, &sym, rversion, ++ ELF_MACHINE_JMP_SLOT); ++ if (sym != NULL) ++ _dl_audit_symbind (map, NULL, sym, r_addr_arg, sym_map); ++ } ++#endif + } + + #if defined ELF_MACHINE_IRELATIVE && !defined RTLD_BOOTSTRAP +@@ -158,17 +173,33 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[], + else + { + for (; r < end; ++r) ++ { ++ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)]; ++ void *const r_addr_arg = (void *) (l_addr + r->r_offset); + # ifdef ELF_MACHINE_IRELATIVE +- if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE) +- { +- if (r2 == NULL) +- r2 = r; +- end2 = r; +- } +- else ++ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE) ++ { ++ if (r2 == NULL) ++ r2 = r; ++ end2 = r; ++ continue; ++ } + # endif +- elf_machine_rel (map, scope, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL, +- (void *) (l_addr + r->r_offset), skip_ifunc); ++ elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg, ++ skip_ifunc); ++# if defined SHARED && !defined RTLD_BOOTSTRAP ++ if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT ++ && GLRO(dl_naudit) > 0) ++ { ++ struct link_map *sym_map ++ = RESOLVE_MAP (map, scope, &sym, ++ (struct r_found_version *) NULL, ++ ELF_MACHINE_JMP_SLOT); ++ if (sym != NULL) ++ _dl_audit_symbind (map, NULL , sym,r_addr_arg, sym_map); ++ } ++# endif ++ } + + # ifdef ELF_MACHINE_IRELATIVE + if (r2 != NULL) +diff --git a/elf/sotruss-lib.c b/elf/sotruss-lib.c +index f0a7e55599d76714..e1ac53f327a7571b 100644 +--- a/elf/sotruss-lib.c ++++ b/elf/sotruss-lib.c +@@ -17,6 +17,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include +@@ -232,6 +233,12 @@ uintptr_t + la_symbind (Elf_Sym *sym, unsigned int ndx, uintptr_t *refcook, + uintptr_t *defcook, unsigned int *flags, const char *symname) + { ++ if (*flags & LA_SYMB_NOPLTENTER) ++ warnx ("cannot trace PLT enter (bind-now enabled)"); ++ ++ if (do_exit && *flags & LA_SYMB_NOPLTEXIT) ++ warnx ("cannot trace PLT exit (bind-now enabled)"); ++ + if (!do_exit) + *flags = LA_SYMB_NOPLTEXIT; + +diff --git a/elf/tst-audit24a.c b/elf/tst-audit24a.c +new file mode 100644 +index 0000000000000000..a1781c9b45f18fa0 +--- /dev/null ++++ b/elf/tst-audit24a.c +@@ -0,0 +1,36 @@ ++/* LD_AUDIT test for la_symbind and bind-now. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++int tst_audit24amod1_func1 (void); ++int tst_audit24amod1_func2 (void); ++int tst_audit24amod2_func1 (void); ++ ++int ++do_test (void) ++{ ++ TEST_COMPARE (tst_audit24amod1_func1 (), 1); ++ TEST_COMPARE (tst_audit24amod1_func2 (), 2); ++ TEST_COMPARE (tst_audit24amod2_func1 (), 10); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit24amod1.c b/elf/tst-audit24amod1.c +new file mode 100644 +index 0000000000000000..0289a4abefbc7bbb +--- /dev/null ++++ b/elf/tst-audit24amod1.c +@@ -0,0 +1,31 @@ ++/* Module used by tst-audit24a. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++_Noreturn int ++tst_audit24amod1_func1 (void) ++{ ++ abort (); ++} ++ ++int ++tst_audit24amod1_func2 (void) ++{ ++ return 2; ++} +diff --git a/elf/tst-audit24amod2.c b/elf/tst-audit24amod2.c +new file mode 100644 +index 0000000000000000..1562afc9dfc1b9b3 +--- /dev/null ++++ b/elf/tst-audit24amod2.c +@@ -0,0 +1,25 @@ ++/* Module used by tst-audit24a. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++_Noreturn int ++tst_audit24amod2_func1 (void) ++{ ++ abort (); ++} +diff --git a/elf/tst-audit24b.c b/elf/tst-audit24b.c +new file mode 100644 +index 0000000000000000..567bee52c27f4361 +--- /dev/null ++++ b/elf/tst-audit24b.c +@@ -0,0 +1,37 @@ ++/* LD_AUDIT test for la_symbind and bind-now. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This is similar to tst-audit24a, with the difference this modules ++ does not have the .gnu.version section header. */ ++ ++#include ++#include ++ ++int tst_audit24bmod1_func1 (void); ++int tst_audit24bmod1_func2 (void); ++ ++int ++do_test (void) ++{ ++ TEST_COMPARE (tst_audit24bmod1_func1 (), 1); ++ TEST_COMPARE (tst_audit24bmod1_func2 (), 2); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit24bmod1.c b/elf/tst-audit24bmod1.c +new file mode 100644 +index 0000000000000000..57ce14a01bf72fb6 +--- /dev/null ++++ b/elf/tst-audit24bmod1.c +@@ -0,0 +1,31 @@ ++/* Module used by tst-audit24c. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++int tst_audit24bmod2_func1 (void); ++ ++int ++tst_audit24bmod1_func1 (void) ++{ ++ return -1; ++} ++ ++int ++tst_audit24bmod1_func2 (void) ++{ ++ return tst_audit24bmod2_func1 (); ++} +diff --git a/elf/tst-audit24bmod2.c b/elf/tst-audit24bmod2.c +new file mode 100644 +index 0000000000000000..b298ce0a05bf2db2 +--- /dev/null ++++ b/elf/tst-audit24bmod2.c +@@ -0,0 +1,23 @@ ++/* Module used by tst-audit24b. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++int ++tst_audit24bmod2_func1 (void) ++{ ++ return -1; ++} +diff --git a/elf/tst-audit24c.c b/elf/tst-audit24c.c +new file mode 100644 +index 0000000000000000..46ed328756067276 +--- /dev/null ++++ b/elf/tst-audit24c.c +@@ -0,0 +1,2 @@ ++/* It tests LD_BIND_NOW=1 instead of linking with -Wl,-z,now */ ++#include "tst-audit24a.c" +diff --git a/elf/tst-audit24d.c b/elf/tst-audit24d.c +new file mode 100644 +index 0000000000000000..543f3b86a6bbdead +--- /dev/null ++++ b/elf/tst-audit24d.c +@@ -0,0 +1,36 @@ ++/* LD_AUDIT test for la_symbind and bind-now. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++int tst_audit24dmod1_func1 (void); ++int tst_audit24dmod1_func2 (void); ++int tst_audit24dmod2_func1 (void); ++ ++int ++do_test (void) ++{ ++ TEST_COMPARE (tst_audit24dmod1_func1 (), 1); ++ TEST_COMPARE (tst_audit24dmod1_func2 (), 32); ++ TEST_COMPARE (tst_audit24dmod2_func1 (), 10); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-audit24dmod1.c b/elf/tst-audit24dmod1.c +new file mode 100644 +index 0000000000000000..e563f69d638ac3f5 +--- /dev/null ++++ b/elf/tst-audit24dmod1.c +@@ -0,0 +1,33 @@ ++/* Module used by tst-audit24d. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++int tst_audit24dmod3_func1 (void); ++ ++_Noreturn int ++tst_audit24dmod1_func1 (void) ++{ ++ abort (); ++} ++ ++int ++tst_audit24dmod1_func2 (void) ++{ ++ return 2 + tst_audit24dmod3_func1 ();; ++} +diff --git a/elf/tst-audit24dmod2.c b/elf/tst-audit24dmod2.c +new file mode 100644 +index 0000000000000000..03fe9381281e5790 +--- /dev/null ++++ b/elf/tst-audit24dmod2.c +@@ -0,0 +1,28 @@ ++/* Module for tst-audit24d. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++int tst_audit24dmod4_func1 (void); ++ ++_Noreturn int ++tst_audit24dmod2_func1 (void) ++{ ++ tst_audit24dmod4_func1 (); ++ abort (); ++} +diff --git a/elf/tst-audit24dmod3.c b/elf/tst-audit24dmod3.c +new file mode 100644 +index 0000000000000000..106d517d2887d76c +--- /dev/null ++++ b/elf/tst-audit24dmod3.c +@@ -0,0 +1,31 @@ ++/* Module for tst-audit24d. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++_Noreturn int ++tst_audit24dmod3_func1 (void) ++{ ++ abort (); ++} ++ ++int ++tst_audit24dmod3_func2 (void) ++{ ++ return 4; ++} +diff --git a/elf/tst-audit24dmod4.c b/elf/tst-audit24dmod4.c +new file mode 100644 +index 0000000000000000..1da3b46917ba1083 +--- /dev/null ++++ b/elf/tst-audit24dmod4.c +@@ -0,0 +1,25 @@ ++/* Module for tst-audit24d. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++_Noreturn int ++tst_audit24dmod4_func1 (void) ++{ ++ abort (); ++} +diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c +new file mode 100644 +index 0000000000000000..49173e862516e876 +--- /dev/null ++++ b/elf/tst-audit25a.c +@@ -0,0 +1,129 @@ ++/* Check LD_AUDIT and LD_BIND_NOW. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++void tst_audit25mod1_func1 (void); ++void tst_audit25mod1_func2 (void); ++void tst_audit25mod2_func1 (void); ++void tst_audit25mod2_func2 (void); ++ ++static int ++handle_restart (void) ++{ ++ tst_audit25mod1_func1 (); ++ tst_audit25mod1_func2 (); ++ tst_audit25mod2_func1 (); ++ tst_audit25mod2_func2 (); ++ ++ return 0; ++} ++ ++static inline bool ++startswith (const char *str, const char *pre) ++{ ++ size_t lenpre = strlen (pre); ++ size_t lenstr = strlen (str); ++ return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0; ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ - One or four parameters left if called initially: ++ + path to ld.so optional ++ + "--library-path" optional ++ + the library path optional ++ + the application name */ ++ ++ if (restart) ++ return handle_restart (); ++ ++ setenv ("LD_AUDIT", "tst-auditmod25.so", 0); ++ ++ char *spargv[9]; ++ int i = 0; ++ for (; i < argc - 1; i++) ++ spargv[i] = argv[i + 1]; ++ spargv[i++] = (char *) "--direct"; ++ spargv[i++] = (char *) "--restart"; ++ spargv[i] = NULL; ++ TEST_VERIFY_EXIT (i < array_length (spargv)); ++ ++ { ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit25a", 0, ++ sc_allow_stderr); ++ ++ /* tst-audit25a is build with -Wl,-z,lazy and tst-audit25mod1 with ++ -Wl,-z,now; so only tst_audit25mod3_func1 should be expected to ++ have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT. */ ++ TEST_COMPARE_STRING (result.err.buffer, ++ "la_symbind: tst_audit25mod3_func1 1\n" ++ "la_symbind: tst_audit25mod1_func1 0\n" ++ "la_symbind: tst_audit25mod1_func2 0\n" ++ "la_symbind: tst_audit25mod2_func1 0\n" ++ "la_symbind: tst_audit25mod4_func1 0\n" ++ "la_symbind: tst_audit25mod2_func2 0\n"); ++ ++ support_capture_subprocess_free (&result); ++ } ++ ++ { ++ setenv ("LD_BIND_NOW", "1", 0); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit25a", 0, ++ sc_allow_stderr); ++ ++ /* With LD_BIND_NOW all symbols are expected to have ++ LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT. Also the resolution ++ order is done in breadth-first order. */ ++ TEST_COMPARE_STRING (result.err.buffer, ++ "la_symbind: tst_audit25mod4_func1 1\n" ++ "la_symbind: tst_audit25mod3_func1 1\n" ++ "la_symbind: tst_audit25mod1_func1 1\n" ++ "la_symbind: tst_audit25mod2_func1 1\n" ++ "la_symbind: tst_audit25mod1_func2 1\n" ++ "la_symbind: tst_audit25mod2_func2 1\n"); ++ ++ support_capture_subprocess_free (&result); ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c +new file mode 100644 +index 0000000000000000..a56638d501f9bff5 +--- /dev/null ++++ b/elf/tst-audit25b.c +@@ -0,0 +1,128 @@ ++/* Check LD_AUDIT and LD_BIND_NOW. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int restart; ++#define CMDLINE_OPTIONS \ ++ { "restart", no_argument, &restart, 1 }, ++ ++void tst_audit25mod1_func1 (void); ++void tst_audit25mod1_func2 (void); ++void tst_audit25mod2_func1 (void); ++void tst_audit25mod2_func2 (void); ++ ++static int ++handle_restart (void) ++{ ++ tst_audit25mod1_func1 (); ++ tst_audit25mod1_func2 (); ++ tst_audit25mod2_func1 (); ++ tst_audit25mod2_func2 (); ++ ++ return 0; ++} ++ ++static inline bool ++startswith (const char *str, const char *pre) ++{ ++ size_t lenpre = strlen (pre); ++ size_t lenstr = strlen (str); ++ return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0; ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ /* We must have either: ++ - One or four parameters left if called initially: ++ + path to ld.so optional ++ + "--library-path" optional ++ + the library path optional ++ + the application name */ ++ ++ if (restart) ++ return handle_restart (); ++ ++ setenv ("LD_AUDIT", "tst-auditmod25.so", 0); ++ ++ char *spargv[9]; ++ int i = 0; ++ for (; i < argc - 1; i++) ++ spargv[i] = argv[i + 1]; ++ spargv[i++] = (char *) "--direct"; ++ spargv[i++] = (char *) "--restart"; ++ spargv[i] = NULL; ++ ++ { ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit25a", 0, ++ sc_allow_stderr); ++ ++ /* tst-audit25a and tst-audit25mod1 are built with -Wl,-z,now, but ++ tst-audit25mod2 is built with -Wl,-z,lazy. So only ++ tst_audit25mod4_func1 (called by tst_audit25mod2_func1) should not ++ have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT. */ ++ TEST_COMPARE_STRING (result.err.buffer, ++ "la_symbind: tst_audit25mod3_func1 1\n" ++ "la_symbind: tst_audit25mod1_func1 1\n" ++ "la_symbind: tst_audit25mod2_func1 1\n" ++ "la_symbind: tst_audit25mod1_func2 1\n" ++ "la_symbind: tst_audit25mod2_func2 1\n" ++ "la_symbind: tst_audit25mod4_func1 0\n"); ++ ++ support_capture_subprocess_free (&result); ++ } ++ ++ { ++ setenv ("LD_BIND_NOW", "1", 0); ++ struct support_capture_subprocess result ++ = support_capture_subprogram (spargv[0], spargv); ++ support_capture_subprocess_check (&result, "tst-audit25a", 0, ++ sc_allow_stderr); ++ ++ /* With LD_BIND_NOW all symbols are expected to have ++ LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT. Also the resolution ++ order is done in breadth-first order. */ ++ TEST_COMPARE_STRING (result.err.buffer, ++ "la_symbind: tst_audit25mod4_func1 1\n" ++ "la_symbind: tst_audit25mod3_func1 1\n" ++ "la_symbind: tst_audit25mod1_func1 1\n" ++ "la_symbind: tst_audit25mod2_func1 1\n" ++ "la_symbind: tst_audit25mod1_func2 1\n" ++ "la_symbind: tst_audit25mod2_func2 1\n"); ++ ++ support_capture_subprocess_free (&result); ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION_ARGV do_test ++#include +diff --git a/elf/tst-audit25mod1.c b/elf/tst-audit25mod1.c +new file mode 100644 +index 0000000000000000..a132e34a9b2cf51f +--- /dev/null ++++ b/elf/tst-audit25mod1.c +@@ -0,0 +1,30 @@ ++/* Module used by tst-audit25. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++void tst_audit25mod3_func1 (void); ++ ++void ++tst_audit25mod1_func1 (void) ++{ ++ tst_audit25mod3_func1 (); ++} ++ ++void ++tst_audit25mod1_func2 (void) ++{ ++} +diff --git a/elf/tst-audit25mod2.c b/elf/tst-audit25mod2.c +new file mode 100644 +index 0000000000000000..92da26fa80b202c2 +--- /dev/null ++++ b/elf/tst-audit25mod2.c +@@ -0,0 +1,30 @@ ++/* Module used by tst-audit25. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++void tst_audit25mod4_func1 (void); ++ ++void ++tst_audit25mod2_func1 (void) ++{ ++ tst_audit25mod4_func1 (); ++} ++ ++void ++tst_audit25mod2_func2 (void) ++{ ++} +diff --git a/elf/tst-audit25mod3.c b/elf/tst-audit25mod3.c +new file mode 100644 +index 0000000000000000..af83e8919083adef +--- /dev/null ++++ b/elf/tst-audit25mod3.c +@@ -0,0 +1,22 @@ ++/* Module used by tst-audit25. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++void ++tst_audit25mod3_func1 (void) ++{ ++} +diff --git a/elf/tst-audit25mod4.c b/elf/tst-audit25mod4.c +new file mode 100644 +index 0000000000000000..6cdf34357582da16 +--- /dev/null ++++ b/elf/tst-audit25mod4.c +@@ -0,0 +1,22 @@ ++/* Module used by tst-audit25. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++void ++tst_audit25mod4_func1 (void) ++{ ++} +diff --git a/elf/tst-auditmod24.h b/elf/tst-auditmod24.h +new file mode 100644 +index 0000000000000000..5fdbfef12dac2b2a +--- /dev/null ++++ b/elf/tst-auditmod24.h +@@ -0,0 +1,29 @@ ++/* Auxiliary functions for tst-audit24x. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _TST_AUDITMOD24_H ++#define _TST_AUDITMOD24_H ++ ++static void ++test_symbind_flags (unsigned int flags) ++{ ++ if ((flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) == 0) ++ abort (); ++} ++ ++#endif +diff --git a/elf/tst-auditmod24a.c b/elf/tst-auditmod24a.c +new file mode 100644 +index 0000000000000000..d8e88f3984af1707 +--- /dev/null ++++ b/elf/tst-auditmod24a.c +@@ -0,0 +1,114 @@ ++/* Audit modules for tst-audit24a. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define AUDIT24_COOKIE 0x1 ++#define AUDIT24MOD1_COOKIE 0x2 ++#define AUDIT24MOD2_COOKIE 0x3 ++ ++#ifndef TEST_NAME ++# define TEST_NAME "tst-audit24a" ++#endif ++#ifndef TEST_MOD ++# define TEST_MOD TEST_NAME ++#endif ++#ifndef TEST_FUNC ++# define TEST_FUNC "tst_audit24a" ++#endif ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? TEST_NAME : p + 1; ++ ++ uintptr_t ck = -1; ++ if (strcmp (l_name, TEST_MOD "mod1.so") == 0) ++ ck = AUDIT24MOD1_COOKIE; ++ else if (strcmp (l_name, TEST_MOD "mod2.so") == 0) ++ ck = AUDIT24MOD2_COOKIE; ++ else if (strcmp (l_name, TEST_NAME) == 0) ++ ck = AUDIT24_COOKIE; ++ ++ *cookie = ck; ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++static int ++tst_func1 (void) ++{ ++ return 1; ++} ++ ++static int ++tst_func2 (void) ++{ ++ return 10; ++} ++ ++#if __ELF_NATIVE_CLASS == 64 ++uintptr_t ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#else ++uintptr_t ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#endif ++{ ++ if (*refcook == AUDIT24_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD1_COOKIE) ++ { ++ /* Check if bind-now symbols are advertised to not call the PLT ++ hooks. */ ++ test_symbind_flags (*flags); ++ ++ if (strcmp (symname, TEST_FUNC "mod1_func1") == 0) ++ return (uintptr_t) tst_func1; ++ else if (strcmp (symname, TEST_FUNC "mod1_func2") == 0) ++ return sym->st_value; ++ abort (); ++ } ++ if (*defcook == AUDIT24MOD2_COOKIE ++ && (strcmp (symname, TEST_FUNC "mod2_func1") == 0)) ++ { ++ test_symbind_flags (*flags); ++ ++ return (uintptr_t) tst_func2; ++ } ++ ++ /* malloc functions. */ ++ return sym->st_value; ++ } ++ ++ abort (); ++} +diff --git a/elf/tst-auditmod24b.c b/elf/tst-auditmod24b.c +new file mode 100644 +index 0000000000000000..e98f6d5ec528fe03 +--- /dev/null ++++ b/elf/tst-auditmod24b.c +@@ -0,0 +1,104 @@ ++/* Audit modules for tst-audit24b. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define TEST_NAME "tst-audit24b" ++#define TEST_FUNC "tst_audit24b" ++ ++#define AUDIT24_COOKIE 0x1 ++#define AUDIT24MOD1_COOKIE 0x2 ++#define AUDIT24MOD2_COOKIE 0x3 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? TEST_NAME : p + 1; ++ ++ uintptr_t ck = -1; ++ if (strcmp (l_name, TEST_NAME "mod1.so") == 0) ++ ck = AUDIT24MOD1_COOKIE; ++ else if (strcmp (l_name, TEST_NAME "mod2.so") == 0) ++ ck = AUDIT24MOD2_COOKIE; ++ else if (strcmp (l_name, TEST_NAME) == 0) ++ ck = AUDIT24_COOKIE; ++ ++ *cookie = ck; ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++static int ++tst_func1 (void) ++{ ++ return 1; ++} ++ ++static int ++tst_func2 (void) ++{ ++ return 2; ++} ++ ++#if __ELF_NATIVE_CLASS == 64 ++uintptr_t ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#else ++uintptr_t ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#endif ++{ ++ if (*refcook == AUDIT24_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD1_COOKIE) ++ { ++ if (strcmp (symname, TEST_FUNC "mod1_func1") == 0) ++ return (uintptr_t) tst_func1; ++ else if (strcmp (symname, TEST_FUNC "mod1_func2") == 0) ++ return sym->st_value; ++ abort (); ++ } ++ /* malloc functions. */ ++ return sym->st_value; ++ } ++ else if (*refcook == AUDIT24MOD1_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD2_COOKIE ++ && (strcmp (symname, TEST_FUNC "mod2_func1") == 0)) ++ { ++ test_symbind_flags (*flags); ++ return (uintptr_t) tst_func2; ++ } ++ } ++ ++ abort (); ++} +diff --git a/elf/tst-auditmod24c.c b/elf/tst-auditmod24c.c +new file mode 100644 +index 0000000000000000..67e62c9d332f48a7 +--- /dev/null ++++ b/elf/tst-auditmod24c.c +@@ -0,0 +1,3 @@ ++#define TEST_NAME "tst-audit24c" ++#define TEST_MOD "tst-audit24a" ++#include "tst-auditmod24a.c" +diff --git a/elf/tst-auditmod24d.c b/elf/tst-auditmod24d.c +new file mode 100644 +index 0000000000000000..8c803ecc0a48f21b +--- /dev/null ++++ b/elf/tst-auditmod24d.c +@@ -0,0 +1,120 @@ ++/* Audit module for tst-audit24d. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define AUDIT24_COOKIE 0x0 ++#define AUDIT24MOD1_COOKIE 0x1 ++#define AUDIT24MOD2_COOKIE 0x2 ++#define AUDIT24MOD3_COOKIE 0x3 ++#define AUDIT24MOD4_COOKIE 0x4 ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? "tst-audit24d" : p + 1; ++ ++ uintptr_t ck = -1; ++ if (strcmp (l_name, "tst-audit24dmod1.so") == 0) ++ ck = AUDIT24MOD1_COOKIE; ++ else if (strcmp (l_name, "tst-audit24dmod2.so") == 0) ++ ck = AUDIT24MOD2_COOKIE; ++ else if (strcmp (l_name, "tst-audit24dmod3.so") == 0) ++ ck = AUDIT24MOD3_COOKIE; ++ else if (strcmp (l_name, "tst-audit24dmod.so") == 0) ++ ck = AUDIT24MOD4_COOKIE; ++ else if (strcmp (l_name, "tst-audit24d") == 0) ++ ck = AUDIT24_COOKIE; ++ ++ *cookie = ck; ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++static int ++tst_audit24dmod1_func1 (void) ++{ ++ return 1; ++} ++ ++static int ++tst_audit24dmod2_func1 (void) ++{ ++ return 10; ++} ++ ++static int ++tst_audit24dmod3_func1 (void) ++{ ++ return 30; ++} ++ ++#include ++ ++#if __ELF_NATIVE_CLASS == 64 ++uintptr_t ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#else ++uintptr_t ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#endif ++{ ++ if (*refcook == AUDIT24_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD1_COOKIE) ++ { ++ if (strcmp (symname, "tst_audit24dmod1_func1") == 0) ++ return (uintptr_t) tst_audit24dmod1_func1; ++ else if (strcmp (symname, "tst_audit24dmod1_func2") == 0) ++ return sym->st_value; ++ abort (); ++ } ++ if (*defcook == AUDIT24MOD2_COOKIE ++ && (strcmp (symname, "tst_audit24dmod2_func1") == 0)) ++ return (uintptr_t) tst_audit24dmod2_func1; ++ ++ /* malloc functions. */ ++ return sym->st_value; ++ } ++ else if (*refcook == AUDIT24MOD1_COOKIE) ++ { ++ if (*defcook == AUDIT24MOD3_COOKIE ++ && strcmp (symname, "tst_audit24dmod3_func1") == 0) ++ { ++ test_symbind_flags (*flags); ++ ++ return (uintptr_t) tst_audit24dmod3_func1; ++ } ++ } ++ ++ abort (); ++} +diff --git a/elf/tst-auditmod25.c b/elf/tst-auditmod25.c +new file mode 100644 +index 0000000000000000..526f5c54bc2c3b8c +--- /dev/null ++++ b/elf/tst-auditmod25.c +@@ -0,0 +1,79 @@ ++/* Audit modules for tst-audit25a. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define AUDIT25_COOKIE 0x1 ++#define AUDIT25MOD1_COOKIE 0x2 ++#define AUDIT25MOD2_COOKIE 0x3 ++#define AUDIT25MOD3_COOKIE 0x2 ++#define AUDIT25MOD4_COOKIE 0x3 ++ ++#define TEST_NAME "tst-audit25" ++#define TEST_MOD "tst-audit25" ++#define TEST_FUNC "tst_audit25" ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return LAV_CURRENT; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? TEST_NAME : p + 1; ++ ++ uintptr_t ck = -1; ++ if (strcmp (l_name, TEST_MOD "mod1.so") == 0) ++ ck = AUDIT25MOD1_COOKIE; ++ else if (strcmp (l_name, TEST_MOD "mod2.so") == 0) ++ ck = AUDIT25MOD2_COOKIE; ++ else if (strcmp (l_name, TEST_MOD "mod3.so") == 0) ++ ck = AUDIT25MOD3_COOKIE; ++ else if (strcmp (l_name, TEST_MOD "mod4.so") == 0) ++ ck = AUDIT25MOD4_COOKIE; ++ else if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0) ++ ck = AUDIT25_COOKIE; ++ ++ *cookie = ck; ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++#if __ELF_NATIVE_CLASS == 64 ++uintptr_t ++la_symbind64 (Elf64_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#else ++uintptr_t ++la_symbind32 (Elf32_Sym *sym, unsigned int ndx, ++ uintptr_t *refcook, uintptr_t *defcook, ++ unsigned int *flags, const char *symname) ++#endif ++{ ++ if (*refcook != -1 && *defcook != -1) ++ fprintf (stderr, "la_symbind: %s %u\n", symname, ++ *flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ? 1 : 0); ++ return sym->st_value; ++} +diff --git a/sysdeps/generic/dl-lookupcfg.h b/sysdeps/generic/dl-lookupcfg.h +index e7d37170147aba83..7412c6391b0c3e02 100644 +--- a/sysdeps/generic/dl-lookupcfg.h ++++ b/sysdeps/generic/dl-lookupcfg.h +@@ -26,3 +26,6 @@ + #define DL_FIXUP_VALUE_CODE_ADDR(value) (value) + #define DL_FIXUP_VALUE_ADDR(value) (value) + #define DL_FIXUP_ADDR_VALUE(addr) (addr) ++#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) ++#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ (*value) = st_value; +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 73f4863fd43922b9..d4f70211c34d1c59 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1299,7 +1299,10 @@ void _dl_audit_objclose (struct link_map *l) + /* Call the la_preinit from the audit modules for the link_map L. */ + void _dl_audit_preinit (struct link_map *l); + +-/* Call the la_symbind{32,64} from the audit modules for the link_map L. */ ++/* Call the la_symbind{32,64} from the audit modules for the link_map L. If ++ RELOC_RESULT is NULL it assumes the symbol to be bind-now and will set ++ the flags with LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT prior calling ++ la_symbind{32,64}. */ + void _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + const ElfW(Sym) *defsym, DL_FIXUP_VALUE_TYPE *value, + lookup_t result) +diff --git a/sysdeps/hppa/dl-lookupcfg.h b/sysdeps/hppa/dl-lookupcfg.h +index 38db345936cb6335..c3fea1fe5776b17a 100644 +--- a/sysdeps/hppa/dl-lookupcfg.h ++++ b/sysdeps/hppa/dl-lookupcfg.h +@@ -80,3 +80,6 @@ void attribute_hidden _dl_unmap (struct link_map *map); + #define DL_FIXUP_VALUE_CODE_ADDR(value) ((value).ip) + #define DL_FIXUP_VALUE_ADDR(value) ((uintptr_t) &(value)) + #define DL_FIXUP_ADDR_VALUE(addr) (*(struct fdesc *) (addr)) ++#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) ++#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ (*value) = *(struct fdesc *) (st_value) +diff --git a/sysdeps/ia64/dl-lookupcfg.h b/sysdeps/ia64/dl-lookupcfg.h +index 48f91202c43f8fda..97ad4b70794135a2 100644 +--- a/sysdeps/ia64/dl-lookupcfg.h ++++ b/sysdeps/ia64/dl-lookupcfg.h +@@ -74,3 +74,6 @@ extern void attribute_hidden _dl_unmap (struct link_map *map); + + #define DL_FIXUP_VALUE_ADDR(value) ((uintptr_t) &(value)) + #define DL_FIXUP_ADDR_VALUE(addr) (*(struct fdesc *) (addr)) ++#define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) ++#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ (*value) = *(struct fdesc *) (st_value) +diff --git a/sysdeps/powerpc/dl-lookupcfg.h b/sysdeps/powerpc/dl-lookupcfg.h +new file mode 100644 +index 0000000000000000..25abcc1d12b15bfc +--- /dev/null ++++ b/sysdeps/powerpc/dl-lookupcfg.h +@@ -0,0 +1,39 @@ ++/* Configuration of lookup functions. PowerPC version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define DL_FIXUP_VALUE_TYPE ElfW(Addr) ++#define DL_FIXUP_MAKE_VALUE(map, addr) (addr) ++#define DL_FIXUP_VALUE_CODE_ADDR(value) (value) ++#define DL_FIXUP_VALUE_ADDR(value) (value) ++#define DL_FIXUP_ADDR_VALUE(addr) (addr) ++#if __WORDSIZE == 64 && _CALL_ELF == 1 ++/* We need to correctly set the audit modules value for bind-now. */ ++# define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) \ ++ (((Elf64_FuncDesc *)(addr))->fd_func) ++# define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ ({ \ ++ Elf64_FuncDesc *opd = (Elf64_FuncDesc *) (value); \ ++ opd->fd_func = (st_value); \ ++ if ((new_value) != (uintptr_t) (st_value)) \ ++ opd->fd_toc = ((Elf64_FuncDesc *)(new_value))->fd_toc; \ ++ }) ++#else ++# define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) ++# define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ (*value) = st_value; ++#endif diff --git a/SOURCES/glibc-rh2047981-34.patch b/SOURCES/glibc-rh2047981-34.patch new file mode 100644 index 0000000..8809b82 --- /dev/null +++ b/SOURCES/glibc-rh2047981-34.patch @@ -0,0 +1,1042 @@ +commit ce9a68c57c260c8417afc93972849ac9ad243ec4 +Author: Ben Woodard +Date: Mon Jan 24 10:46:18 2022 -0300 + + elf: Fix runtime linker auditing on aarch64 (BZ #26643) + + The rtld audit support show two problems on aarch64: + + 1. _dl_runtime_resolve does not preserve x8, the indirect result + location register, which might generate wrong result calls + depending of the function signature. + + 2. The NEON Q registers pushed onto the stack by _dl_runtime_resolve + were twice the size of D registers extracted from the stack frame by + _dl_runtime_profile. + + While 2. might result in wrong information passed on the PLT tracing, + 1. generates wrong runtime behaviour. + + The aarch64 rtld audit support is changed to: + + * Both La_aarch64_regs and La_aarch64_retval are expanded to include + both x8 and the full sized NEON V registers, as defined by the + ABI. + + * dl_runtime_profile needed to extract registers saved by + _dl_runtime_resolve and put them into the new correctly sized + La_aarch64_regs structure. + + * The LAV_CURRENT check is change to only accept new audit modules + to avoid the undefined behavior of not save/restore x8. + + * Different than other architectures, audit modules older than + LAV_CURRENT are rejected (both La_aarch64_regs and La_aarch64_retval + changed their layout and there are no requirements to support multiple + audit interface with the inherent aarch64 issues). + + * A new field is also reserved on both La_aarch64_regs and + La_aarch64_retval to support variant pcs symbols. + + Similar to x86, a new La_aarch64_vector type to represent the NEON + register is added on the La_aarch64_regs (so each type can be accessed + directly). + + Since LAV_CURRENT was already bumped to support bind-now, there is + no need to increase it again. + + Checked on aarch64-linux-gnu. + + Co-authored-by: Adhemerval Zanella + Reviewed-by: Szabolcs Nagy + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +Conflicts: + elf/rtld.c + sysdeps/aarch64/Makefile + Rewrite slightly for inclusion in elf/ testing. + +diff --git a/elf/rtld.c b/elf/rtld.c +index caa980dbda3d1a72..aee5ca357f66121e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -49,6 +49,7 @@ + #include + #include + #include ++#include + + #include + +@@ -1002,7 +1003,7 @@ file=%s [%lu]; audit interface function la_version returned zero; ignored.\n", + return; + } + +- if (lav > LAV_CURRENT) ++ if (!_dl_audit_check_version (lav)) + { + _dl_debug_printf ("\ + ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n", +diff --git a/sysdeps/aarch64/Makefile b/sysdeps/aarch64/Makefile +index 3ec78fefc6dd5797..794ea7d13ae2737f 100644 +--- a/sysdeps/aarch64/Makefile ++++ b/sysdeps/aarch64/Makefile +@@ -4,6 +4,26 @@ ifeq ($(subdir),elf) + sysdep-dl-routines += tlsdesc dl-tlsdesc + gen-as-const-headers += dl-link.sym + ++tests += tst-audit26 \ ++ tst-audit27 ++ ++modules-names += \ ++ tst-audit26mod \ ++ tst-auditmod26 \ ++ tst-audit27mod \ ++ tst-auditmod27 ++ ++$(objpfx)tst-audit26: $(objpfx)tst-audit26mod.so \ ++ $(objpfx)tst-auditmod26.so ++LDFLAGS-tst-audit26 += -Wl,-z,lazy ++tst-audit26-ENV = LD_AUDIT=$(objpfx)tst-auditmod26.so ++ ++$(objpfx)tst-audit27: $(objpfx)tst-audit27mod.so \ ++ $(objpfx)tst-auditmod27.so ++$(objpfx)tst-audit27mod.so: $(libsupport) ++LDFLAGS-tst-audit27 += -Wl,-z,lazy ++tst-audit27-ENV = LD_AUDIT=$(objpfx)tst-auditmod27.so ++ + ifeq (yes,$(aarch64-variant-pcs)) + tests += tst-vpcs + modules-names += tst-vpcs-mod +diff --git a/sysdeps/aarch64/bits/link.h b/sysdeps/aarch64/bits/link.h +index 5a7fc1ccd494b2a7..f4f844bfefdaf2f5 100644 +--- a/sysdeps/aarch64/bits/link.h ++++ b/sysdeps/aarch64/bits/link.h +@@ -20,23 +20,31 @@ + # error "Never include directly; use instead." + #endif + ++typedef union ++{ ++ float s; ++ double d; ++ long double q; ++} La_aarch64_vector; ++ + /* Registers for entry into PLT on AArch64. */ + typedef struct La_aarch64_regs + { +- uint64_t lr_xreg[8]; +- uint64_t lr_dreg[8]; +- uint64_t lr_sp; +- uint64_t lr_lr; ++ uint64_t lr_xreg[9]; ++ La_aarch64_vector lr_vreg[8]; ++ uint64_t lr_sp; ++ uint64_t lr_lr; ++ void *lr_vpcs; + } La_aarch64_regs; + + /* Return values for calls from PLT on AArch64. */ + typedef struct La_aarch64_retval + { +- /* Up to two integer registers can be used for a return value. */ +- uint64_t lrv_xreg[2]; +- /* Up to four D registers can be used for a return value. */ +- uint64_t lrv_dreg[4]; +- ++ /* Up to eight integer registers can be used for a return value. */ ++ uint64_t lrv_xreg[8]; ++ /* Up to eight V registers can be used for a return value. */ ++ La_aarch64_vector lrv_vreg[8]; ++ void *lrv_vpcs; + } La_aarch64_retval; + __BEGIN_DECLS + +diff --git a/sysdeps/aarch64/dl-audit-check.h b/sysdeps/aarch64/dl-audit-check.h +new file mode 100644 +index 0000000000000000..e324339a1d4abec3 +--- /dev/null ++++ b/sysdeps/aarch64/dl-audit-check.h +@@ -0,0 +1,28 @@ ++/* rtld-audit version check. AArch64 version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++static inline bool ++_dl_audit_check_version (unsigned int lav) ++{ ++ /* Audit version 1 do not save x8 or NEON registers, which required ++ changing La_aarch64_regs and La_aarch64_retval layout (BZ#26643). The ++ missing indirect result save/restore makes _dl_runtime_profile ++ potentially trigger undefined behavior if the function returns a large ++ struct (even when PLT trace is not requested). */ ++ return lav == LAV_CURRENT; ++} +diff --git a/sysdeps/aarch64/dl-link.sym b/sysdeps/aarch64/dl-link.sym +index d67d28b40ce7d4ff..cb4dcdcbed0db492 100644 +--- a/sysdeps/aarch64/dl-link.sym ++++ b/sysdeps/aarch64/dl-link.sym +@@ -7,9 +7,11 @@ DL_SIZEOF_RG sizeof(struct La_aarch64_regs) + DL_SIZEOF_RV sizeof(struct La_aarch64_retval) + + DL_OFFSET_RG_X0 offsetof(struct La_aarch64_regs, lr_xreg) +-DL_OFFSET_RG_D0 offsetof(struct La_aarch64_regs, lr_dreg) ++DL_OFFSET_RG_V0 offsetof(struct La_aarch64_regs, lr_vreg) + DL_OFFSET_RG_SP offsetof(struct La_aarch64_regs, lr_sp) + DL_OFFSET_RG_LR offsetof(struct La_aarch64_regs, lr_lr) ++DL_OFFSET_RG_VPCS offsetof(struct La_aarch64_regs, lr_vpcs) + + DL_OFFSET_RV_X0 offsetof(struct La_aarch64_retval, lrv_xreg) +-DL_OFFSET_RV_D0 offsetof(struct La_aarch64_retval, lrv_dreg) ++DL_OFFSET_RV_V0 offsetof(struct La_aarch64_retval, lrv_vreg) ++DL_OFFSET_RV_VPCS offsetof(struct La_aarch64_retval, lrv_vpcs) +diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S +index 18740398e63fdf97..a83e7fc5f97047e2 100644 +--- a/sysdeps/aarch64/dl-trampoline.S ++++ b/sysdeps/aarch64/dl-trampoline.S +@@ -44,7 +44,8 @@ _dl_runtime_resolve: + + cfi_rel_offset (lr, 8) + +- /* Save arguments. */ ++ /* Note: Saving x9 is not required by the ABI but the assembler requires ++ the immediate values of operand 3 to be a multiple of 16 */ + stp x8, x9, [sp, #-(80+8*16)]! + cfi_adjust_cfa_offset (80+8*16) + cfi_rel_offset (x8, 0) +@@ -135,7 +136,7 @@ _dl_runtime_profile: + Stack frame layout: + [sp, #...] lr + [sp, #...] &PLTGOT[n] +- [sp, #96] La_aarch64_regs ++ [sp, #256] La_aarch64_regs + [sp, #48] La_aarch64_retval + [sp, #40] frame size return from pltenter + [sp, #32] dl_profile_call saved x1 +@@ -176,19 +177,25 @@ _dl_runtime_profile: + stp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] + cfi_rel_offset (x6, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 0) + cfi_rel_offset (x7, OFFSET_RG + DL_OFFSET_RG_X0 + 16*3 + 8) +- +- stp d0, d1, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0] +- cfi_rel_offset (d0, OFFSET_RG + DL_OFFSET_RG_D0 + 16*0) +- cfi_rel_offset (d1, OFFSET_RG + DL_OFFSET_RG_D0 + 16*0 + 8) +- stp d2, d3, [X29, #OFFSET_RG+ DL_OFFSET_RG_D0 + 16*1] +- cfi_rel_offset (d2, OFFSET_RG + DL_OFFSET_RG_D0 + 16*1 + 0) +- cfi_rel_offset (d3, OFFSET_RG + DL_OFFSET_RG_D0 + 16*1 + 8) +- stp d4, d5, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2] +- cfi_rel_offset (d4, OFFSET_RG + DL_OFFSET_RG_D0 + 16*2 + 0) +- cfi_rel_offset (d5, OFFSET_RG + DL_OFFSET_RG_D0 + 16*2 + 8) +- stp d6, d7, [X29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3] +- cfi_rel_offset (d6, OFFSET_RG + DL_OFFSET_RG_D0 + 16*3 + 0) +- cfi_rel_offset (d7, OFFSET_RG + DL_OFFSET_RG_D0 + 16*3 + 8) ++ str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4 + 0] ++ cfi_rel_offset (x8, OFFSET_RG + DL_OFFSET_RG_X0 + 16*4 + 0) ++ /* Note 8 bytes of padding is in the stack frame for alignment */ ++ ++ stp q0, q1, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] ++ cfi_rel_offset (q0, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0) ++ cfi_rel_offset (q1, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0 + 16) ++ stp q2, q3, [X29, #OFFSET_RG+ DL_OFFSET_RG_V0 + 32*1] ++ cfi_rel_offset (q2, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 0) ++ cfi_rel_offset (q3, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 16) ++ stp q4, q5, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] ++ cfi_rel_offset (q4, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 0) ++ cfi_rel_offset (q5, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 16) ++ stp q6, q7, [X29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] ++ cfi_rel_offset (q6, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 0) ++ cfi_rel_offset (q7, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 16) ++ ++ /* No APCS extension supported. */ ++ str xzr, [X29, #OFFSET_RG + DL_OFFSET_RG_VPCS] + + add x0, x29, #SF_SIZE + 16 + ldr x1, [x29, #OFFSET_LR] +@@ -227,10 +234,11 @@ _dl_runtime_profile: + ldp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] + ldp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] + ldp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] +- ldp d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0] +- ldp d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1] +- ldp d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2] +- ldp d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3] ++ ldr x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] ++ ldp q0, q1, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] ++ ldp q2, q3, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1] ++ ldp q4, q5, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] ++ ldp q6, q7, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] + + cfi_def_cfa_register (sp) + ldp x29, x30, [x29, #0] +@@ -264,14 +272,22 @@ _dl_runtime_profile: + ldp x2, x3, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*1] + ldp x4, x5, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*2] + ldp x6, x7, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*3] +- ldp d0, d1, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*0] +- ldp d2, d3, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*1] +- ldp d4, d5, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*2] +- ldp d6, d7, [x29, #OFFSET_RG + DL_OFFSET_RG_D0 + 16*3] ++ ldr x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] ++ ldp q0, q1, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0] ++ ldp q2, q3, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1] ++ ldp q4, q5, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2] ++ ldp q6, q7, [x29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3] + blr ip0 +- stp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0] +- stp d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0] +- stp d2, d3, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*1] ++ stp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*0] ++ stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] ++ stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] ++ stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] ++ str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] ++ stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] ++ stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] ++ stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] ++ stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] ++ str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS] + + /* Setup call to pltexit */ + ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] +@@ -279,9 +295,16 @@ _dl_runtime_profile: + add x3, x29, #OFFSET_RV + bl _dl_audit_pltexit + +- ldp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0] +- ldp d0, d1, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*0] +- ldp d2, d3, [x29, #OFFSET_RV + DL_OFFSET_RV_D0 + 16*1] ++ ldp x0, x1, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*0] ++ ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] ++ ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] ++ ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] ++ ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4] ++ ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] ++ ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] ++ ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] ++ ldp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] ++ + /* LR from within La_aarch64_reg */ + ldr lr, [x29, #OFFSET_RG + DL_OFFSET_RG_LR] + cfi_restore(lr) +diff --git a/sysdeps/aarch64/tst-audit26.c b/sysdeps/aarch64/tst-audit26.c +new file mode 100644 +index 0000000000000000..46de8acd219cb8bc +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit26.c +@@ -0,0 +1,37 @@ ++/* Check LD_AUDIT for aarch64 ABI specifics. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include "tst-audit26mod.h" ++ ++int ++do_test (void) ++{ ++ /* Returning a large struct uses 'x8' as indirect result location. */ ++ struct large_struct r = tst_audit26_func (ARG1, ARG2, ARG3); ++ ++ struct large_struct e = set_large_struct (ARG1, ARG2, ARG3); ++ ++ TEST_COMPARE_BLOB (r.a, sizeof (r.a), e.a, sizeof (e.a)); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/aarch64/tst-audit26mod.c b/sysdeps/aarch64/tst-audit26mod.c +new file mode 100644 +index 0000000000000000..67d5ffce7288b34c +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit26mod.c +@@ -0,0 +1,33 @@ ++/* Check LD_AUDIT for aarch64 ABI specifics. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include "tst-audit26mod.h" ++ ++struct large_struct ++tst_audit26_func (char a, short b, long int c) ++{ ++ if (a != ARG1) ++ abort (); ++ if (b != ARG2) ++ abort (); ++ if (c != ARG3) ++ abort (); ++ ++ return set_large_struct (a, b, c); ++} +diff --git a/sysdeps/aarch64/tst-audit26mod.h b/sysdeps/aarch64/tst-audit26mod.h +new file mode 100644 +index 0000000000000000..f80409f96bae6c82 +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit26mod.h +@@ -0,0 +1,50 @@ ++/* Check LD_AUDIT for aarch64 specific ABI. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _TST_AUDIT27MOD_H ++#define _TST_AUDIT27MOD_H 1 ++ ++#include ++ ++struct large_struct ++{ ++ char a[16]; ++ short b[8]; ++ long int c[4]; ++}; ++ ++static inline struct large_struct ++set_large_struct (char a, short b, long int c) ++{ ++ struct large_struct r; ++ for (int i = 0; i < array_length (r.a); i++) ++ r.a[i] = a; ++ for (int i = 0; i < array_length (r.b); i++) ++ r.b[i] = b; ++ for (int i = 0; i < array_length (r.c); i++) ++ r.c[i] = c; ++ return r; ++} ++ ++#define ARG1 0x12 ++#define ARG2 0x1234 ++#define ARG3 0x12345678 ++ ++struct large_struct tst_audit26_func (char a, short b, long int c); ++ ++#endif +diff --git a/sysdeps/aarch64/tst-audit27.c b/sysdeps/aarch64/tst-audit27.c +new file mode 100644 +index 0000000000000000..5ebc09771f845af0 +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit27.c +@@ -0,0 +1,64 @@ ++/* Check LD_AUDIT for aarch64 ABI specifics. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include "tst-audit27mod.h" ++ ++int ++do_test (void) ++{ ++ { ++ float r = tst_audit27_func_float (FUNC_FLOAT_ARG0, FUNC_FLOAT_ARG1, ++ FUNC_FLOAT_ARG2, FUNC_FLOAT_ARG3, ++ FUNC_FLOAT_ARG4, FUNC_FLOAT_ARG5, ++ FUNC_FLOAT_ARG6, FUNC_FLOAT_ARG7); ++ if (r != FUNC_FLOAT_RET) ++ FAIL_EXIT1 ("tst_audit27_func_float() returned %a, expected %a", ++ r, FUNC_FLOAT_RET); ++ } ++ ++ { ++ double r = tst_audit27_func_double (FUNC_DOUBLE_ARG0, FUNC_DOUBLE_ARG1, ++ FUNC_DOUBLE_ARG2, FUNC_DOUBLE_ARG3, ++ FUNC_DOUBLE_ARG4, FUNC_DOUBLE_ARG5, ++ FUNC_DOUBLE_ARG6, FUNC_DOUBLE_ARG7); ++ if (r != FUNC_DOUBLE_RET) ++ FAIL_EXIT1 ("tst_audit27_func_double() returned %la, expected %la", ++ r, FUNC_DOUBLE_RET); ++ } ++ ++ { ++ long double r = tst_audit27_func_ldouble (FUNC_LDOUBLE_ARG0, ++ FUNC_LDOUBLE_ARG1, ++ FUNC_LDOUBLE_ARG2, ++ FUNC_LDOUBLE_ARG3, ++ FUNC_LDOUBLE_ARG4, ++ FUNC_LDOUBLE_ARG5, ++ FUNC_LDOUBLE_ARG6, ++ FUNC_LDOUBLE_ARG7); ++ if (r != FUNC_LDOUBLE_RET) ++ FAIL_EXIT1 ("tst_audit27_func_ldouble() returned %La, expected %La", ++ r, FUNC_LDOUBLE_RET); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/aarch64/tst-audit27mod.c b/sysdeps/aarch64/tst-audit27mod.c +new file mode 100644 +index 0000000000000000..922b518f0af4b97b +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit27mod.c +@@ -0,0 +1,95 @@ ++/* Check LD_AUDIT for aarch64 ABI specifics. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include "tst-audit27mod.h" ++ ++float ++tst_audit27_func_float (float a0, float a1, float a2, float a3, float a4, ++ float a5, float a6, float a7) ++{ ++ if (a0 != FUNC_FLOAT_ARG0) ++ FAIL_EXIT1 ("a0: %a != %a", a0, FUNC_FLOAT_ARG0); ++ if (a1 != FUNC_FLOAT_ARG1) ++ FAIL_EXIT1 ("a1: %a != %a", a1, FUNC_FLOAT_ARG1); ++ if (a2 != FUNC_FLOAT_ARG2) ++ FAIL_EXIT1 ("a2: %a != %a", a2, FUNC_FLOAT_ARG2); ++ if (a3 != FUNC_FLOAT_ARG3) ++ FAIL_EXIT1 ("a3: %a != %a", a3, FUNC_FLOAT_ARG3); ++ if (a4 != FUNC_FLOAT_ARG4) ++ FAIL_EXIT1 ("a4: %a != %a", a4, FUNC_FLOAT_ARG4); ++ if (a5 != FUNC_FLOAT_ARG5) ++ FAIL_EXIT1 ("a5: %a != %a", a5, FUNC_FLOAT_ARG5); ++ if (a6 != FUNC_FLOAT_ARG6) ++ FAIL_EXIT1 ("a6: %a != %a", a6, FUNC_FLOAT_ARG6); ++ if (a7 != FUNC_FLOAT_ARG7) ++ FAIL_EXIT1 ("a7: %a != %a", a7, FUNC_FLOAT_ARG7); ++ ++ return FUNC_FLOAT_RET; ++} ++ ++double ++tst_audit27_func_double (double a0, double a1, double a2, double a3, double a4, ++ double a5, double a6, double a7) ++{ ++ if (a0 != FUNC_DOUBLE_ARG0) ++ FAIL_EXIT1 ("a0: %la != %la", a0, FUNC_DOUBLE_ARG0); ++ if (a1 != FUNC_DOUBLE_ARG1) ++ FAIL_EXIT1 ("a1: %la != %la", a1, FUNC_DOUBLE_ARG1); ++ if (a2 != FUNC_DOUBLE_ARG2) ++ FAIL_EXIT1 ("a2: %la != %la", a2, FUNC_DOUBLE_ARG2); ++ if (a3 != FUNC_DOUBLE_ARG3) ++ FAIL_EXIT1 ("a3: %la != %la", a3, FUNC_DOUBLE_ARG3); ++ if (a4 != FUNC_DOUBLE_ARG4) ++ FAIL_EXIT1 ("a4: %la != %la", a4, FUNC_DOUBLE_ARG4); ++ if (a5 != FUNC_DOUBLE_ARG5) ++ FAIL_EXIT1 ("a5: %la != %la", a5, FUNC_DOUBLE_ARG5); ++ if (a6 != FUNC_DOUBLE_ARG6) ++ FAIL_EXIT1 ("a6: %la != %la", a6, FUNC_DOUBLE_ARG6); ++ if (a7 != FUNC_DOUBLE_ARG7) ++ FAIL_EXIT1 ("a7: %la != %la", a7, FUNC_DOUBLE_ARG7); ++ ++ return FUNC_DOUBLE_RET; ++} ++ ++long double ++tst_audit27_func_ldouble (long double a0, long double a1, long double a2, ++ long double a3, long double a4, long double a5, ++ long double a6, long double a7) ++{ ++ if (a0 != FUNC_LDOUBLE_ARG0) ++ FAIL_EXIT1 ("a0: %La != %La", a0, FUNC_LDOUBLE_ARG0); ++ if (a1 != FUNC_LDOUBLE_ARG1) ++ FAIL_EXIT1 ("a1: %La != %La", a1, FUNC_LDOUBLE_ARG1); ++ if (a2 != FUNC_LDOUBLE_ARG2) ++ FAIL_EXIT1 ("a2: %La != %La", a2, FUNC_LDOUBLE_ARG2); ++ if (a3 != FUNC_LDOUBLE_ARG3) ++ FAIL_EXIT1 ("a3: %La != %La", a3, FUNC_LDOUBLE_ARG3); ++ if (a4 != FUNC_LDOUBLE_ARG4) ++ FAIL_EXIT1 ("a4: %La != %La", a4, FUNC_LDOUBLE_ARG4); ++ if (a5 != FUNC_LDOUBLE_ARG5) ++ FAIL_EXIT1 ("a5: %La != %La", a5, FUNC_LDOUBLE_ARG5); ++ if (a6 != FUNC_LDOUBLE_ARG6) ++ FAIL_EXIT1 ("a6: %La != %La", a6, FUNC_LDOUBLE_ARG6); ++ if (a7 != FUNC_LDOUBLE_ARG7) ++ FAIL_EXIT1 ("a7: %La != %La", a7, FUNC_LDOUBLE_ARG7); ++ ++ return FUNC_LDOUBLE_RET; ++} +diff --git a/sysdeps/aarch64/tst-audit27mod.h b/sysdeps/aarch64/tst-audit27mod.h +new file mode 100644 +index 0000000000000000..1709d222ca251e3b +--- /dev/null ++++ b/sysdeps/aarch64/tst-audit27mod.h +@@ -0,0 +1,67 @@ ++/* Check LD_AUDIT for aarch64 specific ABI. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _TST_AUDIT27MOD_H ++#define _TST_AUDIT27MOD_H 1 ++ ++#include ++ ++#define FUNC_FLOAT_ARG0 FLT_MIN ++#define FUNC_FLOAT_ARG1 FLT_MAX ++#define FUNC_FLOAT_ARG2 FLT_EPSILON ++#define FUNC_FLOAT_ARG3 FLT_TRUE_MIN ++#define FUNC_FLOAT_ARG4 0.0f ++#define FUNC_FLOAT_ARG5 1.0f ++#define FUNC_FLOAT_ARG6 2.0f ++#define FUNC_FLOAT_ARG7 3.0f ++#define FUNC_FLOAT_RET 4.0f ++ ++float ++tst_audit27_func_float (float a0, float a1, float a2, float a3, float a4, ++ float a5, float a6, float a7); ++ ++#define FUNC_DOUBLE_ARG0 DBL_MIN ++#define FUNC_DOUBLE_ARG1 DBL_MAX ++#define FUNC_DOUBLE_ARG2 DBL_EPSILON ++#define FUNC_DOUBLE_ARG3 DBL_TRUE_MIN ++#define FUNC_DOUBLE_ARG4 0.0 ++#define FUNC_DOUBLE_ARG5 1.0 ++#define FUNC_DOUBLE_ARG6 2.0 ++#define FUNC_DOUBLE_ARG7 3.0 ++#define FUNC_DOUBLE_RET 0x1.fffffe0000001p+127 ++ ++double ++tst_audit27_func_double (double a0, double a1, double a2, double a3, double a4, ++ double a5, double a6, double a7); ++ ++#define FUNC_LDOUBLE_ARG0 DBL_MAX + 1.0L ++#define FUNC_LDOUBLE_ARG1 DBL_MAX + 2.0L ++#define FUNC_LDOUBLE_ARG2 DBL_MAX + 3.0L ++#define FUNC_LDOUBLE_ARG3 DBL_MAX + 4.0L ++#define FUNC_LDOUBLE_ARG4 DBL_MAX + 5.0L ++#define FUNC_LDOUBLE_ARG5 DBL_MAX + 6.0L ++#define FUNC_LDOUBLE_ARG6 DBL_MAX + 7.0L ++#define FUNC_LDOUBLE_ARG7 DBL_MAX + 8.0L ++#define FUNC_LDOUBLE_RET 0x1.fffffffffffff000000000000001p+1023L ++ ++long double ++tst_audit27_func_ldouble (long double a0, long double a1, long double a2, ++ long double a3, long double a4, long double a5, ++ long double a6, long double a7); ++ ++#endif +diff --git a/sysdeps/aarch64/tst-auditmod26.c b/sysdeps/aarch64/tst-auditmod26.c +new file mode 100644 +index 0000000000000000..b03b6baed9aeb528 +--- /dev/null ++++ b/sysdeps/aarch64/tst-auditmod26.c +@@ -0,0 +1,103 @@ ++/* Check LD_AUDIT for aarch64 specific ABI. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "tst-audit26mod.h" ++ ++#define TEST_NAME "tst-audit26" ++ ++#define AUDIT26_COOKIE 0 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ return v; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? map->l_name : p + 1; ++ uintptr_t ck = -1; ++ if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0) ++ ck = AUDIT26_COOKIE; ++ *cookie = ck; ++ printf ("objopen: %ld, %s [cookie=%ld]\n", lmid, l_name, ck); ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++ElfW(Addr) ++la_aarch64_gnu_pltenter (ElfW(Sym) *sym __attribute__ ((unused)), ++ unsigned int ndx __attribute__ ((unused)), ++ uintptr_t *refcook, uintptr_t *defcook, ++ La_aarch64_regs *regs, unsigned int *flags, ++ const char *symname, long int *framesizep) ++{ ++ printf ("pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n", ++ symname, (long int) sym->st_value, ndx, *flags); ++ ++ if (strcmp (symname, "tst_audit26_func") == 0) ++ { ++ assert (regs->lr_xreg[0] == ARG1); ++ assert (regs->lr_xreg[1] == ARG2); ++ assert (regs->lr_xreg[2] == ARG3); ++ } ++ else ++ abort (); ++ ++ assert (regs->lr_vpcs == 0); ++ ++ /* Clobber 'x8'. */ ++ asm volatile ("mov x8, -1" : : : "x8"); ++ ++ *framesizep = 1024; ++ ++ return sym->st_value; ++} ++ ++unsigned int ++la_aarch64_gnu_pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, ++ const struct La_aarch64_regs *inregs, ++ struct La_aarch64_retval *outregs, const char *symname) ++{ ++ printf ("pltexit: symname=%s, st_value=%#lx, ndx=%u\n", ++ symname, (long int) sym->st_value, ndx); ++ ++ if (strcmp (symname, "tst_audit26_func") == 0) ++ { ++ assert (inregs->lr_xreg[0] == ARG1); ++ assert (inregs->lr_xreg[1] == ARG2); ++ assert (inregs->lr_xreg[2] == ARG3); ++ } ++ else ++ abort (); ++ ++ assert (inregs->lr_vpcs == 0); ++ assert (outregs->lrv_vpcs == 0); ++ ++ /* Clobber 'x8'. */ ++ asm volatile ("mov x8, -1" : : : "x8"); ++ ++ return 0; ++} +diff --git a/sysdeps/aarch64/tst-auditmod27.c b/sysdeps/aarch64/tst-auditmod27.c +new file mode 100644 +index 0000000000000000..21132c2985dab7b2 +--- /dev/null ++++ b/sysdeps/aarch64/tst-auditmod27.c +@@ -0,0 +1,180 @@ ++/* Check LD_AUDIT for aarch64 specific ABI. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "tst-audit27mod.h" ++ ++#define TEST_NAME "tst-audit27" ++ ++#define AUDIT27_COOKIE 0 ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ return v; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ const char *p = strrchr (map->l_name, '/'); ++ const char *l_name = p == NULL ? map->l_name : p + 1; ++ uintptr_t ck = -1; ++ if (strncmp (l_name, TEST_NAME, strlen (TEST_NAME)) == 0) ++ ck = AUDIT27_COOKIE; ++ *cookie = ck; ++ printf ("objopen: %ld, %s [%ld]\n", lmid, l_name, ck); ++ return ck == -1 ? 0 : LA_FLG_BINDFROM | LA_FLG_BINDTO; ++} ++ ++ElfW(Addr) ++la_aarch64_gnu_pltenter (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, La_aarch64_regs *regs, ++ unsigned int *flags, const char *symname, ++ long int *framesizep) ++{ ++ printf ("pltenter: symname=%s, st_value=%#lx, ndx=%u, flags=%u\n", ++ symname, (long int) sym->st_value, ndx, *flags); ++ ++ if (strcmp (symname, "tst_audit27_func_float") == 0) ++ { ++ assert (regs->lr_vreg[0].s == FUNC_FLOAT_ARG0); ++ assert (regs->lr_vreg[1].s == FUNC_FLOAT_ARG1); ++ assert (regs->lr_vreg[2].s == FUNC_FLOAT_ARG2); ++ assert (regs->lr_vreg[3].s == FUNC_FLOAT_ARG3); ++ assert (regs->lr_vreg[4].s == FUNC_FLOAT_ARG4); ++ assert (regs->lr_vreg[5].s == FUNC_FLOAT_ARG5); ++ assert (regs->lr_vreg[6].s == FUNC_FLOAT_ARG6); ++ assert (regs->lr_vreg[7].s == FUNC_FLOAT_ARG7); ++ } ++ else if (strcmp (symname, "tst_audit27_func_double") == 0) ++ { ++ assert (regs->lr_vreg[0].d == FUNC_DOUBLE_ARG0); ++ assert (regs->lr_vreg[1].d == FUNC_DOUBLE_ARG1); ++ assert (regs->lr_vreg[2].d == FUNC_DOUBLE_ARG2); ++ assert (regs->lr_vreg[3].d == FUNC_DOUBLE_ARG3); ++ assert (regs->lr_vreg[4].d == FUNC_DOUBLE_ARG4); ++ assert (regs->lr_vreg[5].d == FUNC_DOUBLE_ARG5); ++ assert (regs->lr_vreg[6].d == FUNC_DOUBLE_ARG6); ++ assert (regs->lr_vreg[7].d == FUNC_DOUBLE_ARG7); ++ } ++ else if (strcmp (symname, "tst_audit27_func_ldouble") == 0) ++ { ++ assert (regs->lr_vreg[0].q == FUNC_LDOUBLE_ARG0); ++ assert (regs->lr_vreg[1].q == FUNC_LDOUBLE_ARG1); ++ assert (regs->lr_vreg[2].q == FUNC_LDOUBLE_ARG2); ++ assert (regs->lr_vreg[3].q == FUNC_LDOUBLE_ARG3); ++ assert (regs->lr_vreg[4].q == FUNC_LDOUBLE_ARG4); ++ assert (regs->lr_vreg[5].q == FUNC_LDOUBLE_ARG5); ++ assert (regs->lr_vreg[6].q == FUNC_LDOUBLE_ARG6); ++ assert (regs->lr_vreg[7].q == FUNC_LDOUBLE_ARG7); ++ } ++ else ++ abort (); ++ ++ assert (regs->lr_vpcs == 0); ++ ++ /* Clobber the q registers on exit. */ ++ uint8_t v = 0xff; ++ asm volatile ("dup v0.8b, %w0" : : "r" (v) : "v0"); ++ asm volatile ("dup v1.8b, %w0" : : "r" (v) : "v1"); ++ asm volatile ("dup v2.8b, %w0" : : "r" (v) : "v2"); ++ asm volatile ("dup v3.8b, %w0" : : "r" (v) : "v3"); ++ asm volatile ("dup v4.8b, %w0" : : "r" (v) : "v4"); ++ asm volatile ("dup v5.8b, %w0" : : "r" (v) : "v5"); ++ asm volatile ("dup v6.8b, %w0" : : "r" (v) : "v6"); ++ asm volatile ("dup v7.8b, %w0" : : "r" (v) : "v7"); ++ ++ *framesizep = 1024; ++ ++ return sym->st_value; ++} ++ ++unsigned int ++la_aarch64_gnu_pltexit (ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook, ++ uintptr_t *defcook, ++ const struct La_aarch64_regs *inregs, ++ struct La_aarch64_retval *outregs, ++ const char *symname) ++{ ++ printf ("pltexit: symname=%s, st_value=%#lx, ndx=%u\n", ++ symname, (long int) sym->st_value, ndx); ++ ++ if (strcmp (symname, "tst_audit27_func_float") == 0) ++ { ++ assert (inregs->lr_vreg[0].s == FUNC_FLOAT_ARG0); ++ assert (inregs->lr_vreg[1].s == FUNC_FLOAT_ARG1); ++ assert (inregs->lr_vreg[2].s == FUNC_FLOAT_ARG2); ++ assert (inregs->lr_vreg[3].s == FUNC_FLOAT_ARG3); ++ assert (inregs->lr_vreg[4].s == FUNC_FLOAT_ARG4); ++ assert (inregs->lr_vreg[5].s == FUNC_FLOAT_ARG5); ++ assert (inregs->lr_vreg[6].s == FUNC_FLOAT_ARG6); ++ assert (inregs->lr_vreg[7].s == FUNC_FLOAT_ARG7); ++ ++ assert (outregs->lrv_vreg[0].s == FUNC_FLOAT_RET); ++ } ++ else if (strcmp (symname, "tst_audit27_func_double") == 0) ++ { ++ assert (inregs->lr_vreg[0].d == FUNC_DOUBLE_ARG0); ++ assert (inregs->lr_vreg[1].d == FUNC_DOUBLE_ARG1); ++ assert (inregs->lr_vreg[2].d == FUNC_DOUBLE_ARG2); ++ assert (inregs->lr_vreg[3].d == FUNC_DOUBLE_ARG3); ++ assert (inregs->lr_vreg[4].d == FUNC_DOUBLE_ARG4); ++ assert (inregs->lr_vreg[5].d == FUNC_DOUBLE_ARG5); ++ assert (inregs->lr_vreg[6].d == FUNC_DOUBLE_ARG6); ++ assert (inregs->lr_vreg[7].d == FUNC_DOUBLE_ARG7); ++ ++ assert (outregs->lrv_vreg[0].d == FUNC_DOUBLE_RET); ++ } ++ else if (strcmp (symname, "tst_audit27_func_ldouble") == 0) ++ { ++ assert (inregs->lr_vreg[0].q == FUNC_LDOUBLE_ARG0); ++ assert (inregs->lr_vreg[1].q == FUNC_LDOUBLE_ARG1); ++ assert (inregs->lr_vreg[2].q == FUNC_LDOUBLE_ARG2); ++ assert (inregs->lr_vreg[3].q == FUNC_LDOUBLE_ARG3); ++ assert (inregs->lr_vreg[4].q == FUNC_LDOUBLE_ARG4); ++ assert (inregs->lr_vreg[5].q == FUNC_LDOUBLE_ARG5); ++ assert (inregs->lr_vreg[6].q == FUNC_LDOUBLE_ARG6); ++ assert (inregs->lr_vreg[7].q == FUNC_LDOUBLE_ARG7); ++ ++ assert (outregs->lrv_vreg[0].q == FUNC_LDOUBLE_RET); ++ } ++ else ++ abort (); ++ ++ assert (inregs->lr_vpcs == 0); ++ assert (outregs->lrv_vpcs == 0); ++ ++ /* Clobber the q registers on exit. */ ++ uint8_t v = 0xff; ++ asm volatile ("dup v0.8b, %w0" : : "r" (v) : "v0"); ++ asm volatile ("dup v1.8b, %w0" : : "r" (v) : "v1"); ++ asm volatile ("dup v2.8b, %w0" : : "r" (v) : "v2"); ++ asm volatile ("dup v3.8b, %w0" : : "r" (v) : "v3"); ++ asm volatile ("dup v4.8b, %w0" : : "r" (v) : "v4"); ++ asm volatile ("dup v5.8b, %w0" : : "r" (v) : "v5"); ++ asm volatile ("dup v6.8b, %w0" : : "r" (v) : "v6"); ++ asm volatile ("dup v7.8b, %w0" : : "r" (v) : "v7"); ++ ++ return 0; ++} +diff --git a/sysdeps/generic/dl-audit-check.h b/sysdeps/generic/dl-audit-check.h +new file mode 100644 +index 0000000000000000..3ab76532868b5895 +--- /dev/null ++++ b/sysdeps/generic/dl-audit-check.h +@@ -0,0 +1,23 @@ ++/* rtld-audit version check. Generic version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++static inline bool ++_dl_audit_check_version (unsigned int lav) ++{ ++ return lav <= LAV_CURRENT; ++} diff --git a/SOURCES/glibc-rh2047981-35.patch b/SOURCES/glibc-rh2047981-35.patch new file mode 100644 index 0000000..92ecdc6 --- /dev/null +++ b/SOURCES/glibc-rh2047981-35.patch @@ -0,0 +1,21 @@ +commit 80a08d0faa9b224019f895800c4d97de4e23e1aa +Author: Szabolcs Nagy +Date: Wed Feb 2 14:03:58 2022 +0000 + + Fix elf/tst-audit25a with default bind now toolchains + + This test relies on lazy binding for the executable so request that + explicitly in case the toolchain defaults to bind now. + +diff --git a/elf/Makefile b/elf/Makefile +index 78147ed2dbcaf4c0..4d16ed1637db8582 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -2130,6 +2130,7 @@ $(objpfx)tst-audit25a: $(objpfx)tst-audit25mod1.so \ + $(objpfx)tst-audit25mod2.so \ + $(objpfx)tst-audit25mod3.so \ + $(objpfx)tst-audit25mod4.so ++LDFLAGS-tst-audit25a = -Wl,-z,lazy + $(objpfx)tst-audit25mod1.so: $(objpfx)tst-audit25mod3.so + LDFLAGS-tst-audit25mod1.so = -Wl,-z,now + $(objpfx)tst-audit25mod2.so: $(objpfx)tst-audit25mod4.so diff --git a/SOURCES/glibc-rh2047981-36.patch b/SOURCES/glibc-rh2047981-36.patch new file mode 100644 index 0000000..ceaec72 --- /dev/null +++ b/SOURCES/glibc-rh2047981-36.patch @@ -0,0 +1,28 @@ +commit fa7ad1df1915c8a62f50e3a5b7e10f9c7118cd7f +Author: H.J. Lu +Date: Sun Feb 6 11:12:24 2022 -0800 + + elf: Replace tst-audit24bmod2.so with tst-audit24bmod2 + + Replace tst-audit24bmod2.so with tst-audit24bmod2 to silence: + + make[2]: Entering directory '/export/gnu/import/git/gitlab/x86-glibc/elf' + Makefile:2201: warning: overriding recipe for target '/export/build/gnu/tools-build/glibc-gitlab/build-x86_64-linux/elf/tst-audit24bmod2.so' + ../Makerules:765: warning: ignoring old recipe for target '/export/build/gnu/tools-build/glibc-gitlab/build-x86_64-linux/elf/tst-audit24bmod2.so' + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index 4d16ed1637db8582..73d347339762fc9e 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -855,7 +855,7 @@ extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + + # filtmod1.so has a special rule + modules-names-nobuild := filtmod1 \ +- tst-audit24bmod1 tst-audit24bmod2.so ++ tst-audit24bmod1 tst-audit24bmod2 + + tests += $(tests-static) + diff --git a/SOURCES/glibc-rh2047981-37.patch b/SOURCES/glibc-rh2047981-37.patch new file mode 100644 index 0000000..8591468 --- /dev/null +++ b/SOURCES/glibc-rh2047981-37.patch @@ -0,0 +1,112 @@ +commit 9e94f57484a2aba0fe67ea2059b5843f651887c2 +Author: Adhemerval Zanella +Date: Fri Feb 4 15:54:59 2022 -0300 + + hppa: Fix bind-now audit (BZ #28857) + + On hppa, a function pointer returned by la_symbind is actually a function + descriptor has the plabel bit set (bit 30). This must be cleared to get + the actual address of the descriptor. If the descriptor has been bound, + the first word of the descriptor is the physical address of theA function, + otherwise, the first word of the descriptor points to a trampoline in the + PLT. + + This patch also adds a workaround on tests because on hppa (and it seems + to be the only ABI I have see it), some shared library adds a dynamic PLT + relocation to am empty symbol name: + + $ readelf -r elf/tst-audit25mod1.so + [...] + Relocation section '.rela.plt' at offset 0x464 contains 6 entries: + Offset Info Type Sym.Value Sym. Name + Addend + 00002008 00000081 R_PARISC_IPLT 508 + [...] + + It breaks some assumptions on the test, where a symbol with an empty + name ("") is passed on la_symbind. + + Checked on x86_64-linux-gnu and hppa-linux-gnu. + +diff --git a/elf/Makefile b/elf/Makefile +index 73d347339762fc9e..6d39b400060a73f3 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -2113,7 +2113,7 @@ $(objpfx)tst-audit24c.out: $(objpfx)tst-auditmod24c.so + $(objpfx)tst-audit24c: $(objpfx)tst-audit24amod1.so \ + $(objpfx)tst-audit24amod2.so + tst-audit24c-ENV = LD_BIND_NOW=1 LD_AUDIT=$(objpfx)tst-auditmod24c.so +-LDFLAGS-tst-audit24b = -Wl,-z,lazy ++LDFLAGS-tst-audit24c = -Wl,-z,lazy + + $(objpfx)tst-audit24d.out: $(objpfx)tst-auditmod24d.so + $(objpfx)tst-audit24d: $(objpfx)tst-audit24dmod1.so \ +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index 72a50717ef60a357..ec9b032eae37c103 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -257,7 +257,8 @@ _dl_audit_symbind (struct link_map *l, struct reloc_result *reloc_result, + reloc_result->flags = flags; + } + +- DL_FIXUP_BINDNOW_RELOC (value, new_value, sym.st_value); ++ if (flags & LA_SYMB_ALTVALUE) ++ DL_FIXUP_BINDNOW_RELOC (value, new_value, sym.st_value); + } + + void +diff --git a/elf/tst-auditmod24a.c b/elf/tst-auditmod24a.c +index d8e88f3984af1707..3075dfae2fd3d288 100644 +--- a/elf/tst-auditmod24a.c ++++ b/elf/tst-auditmod24a.c +@@ -110,5 +110,7 @@ la_symbind32 (Elf32_Sym *sym, unsigned int ndx, + return sym->st_value; + } + +- abort (); ++ if (symname[0] != '\0') ++ abort (); ++ return sym->st_value; + } +diff --git a/elf/tst-auditmod24d.c b/elf/tst-auditmod24d.c +index 8c803ecc0a48f21b..badc6be451ee0357 100644 +--- a/elf/tst-auditmod24d.c ++++ b/elf/tst-auditmod24d.c +@@ -116,5 +116,7 @@ la_symbind32 (Elf32_Sym *sym, unsigned int ndx, + } + } + +- abort (); ++ if (symname[0] != '\0') ++ abort (); ++ return sym->st_value; + } +diff --git a/elf/tst-auditmod25.c b/elf/tst-auditmod25.c +index 526f5c54bc2c3b8c..20640a8daf346b5f 100644 +--- a/elf/tst-auditmod25.c ++++ b/elf/tst-auditmod25.c +@@ -72,7 +72,7 @@ la_symbind32 (Elf32_Sym *sym, unsigned int ndx, + unsigned int *flags, const char *symname) + #endif + { +- if (*refcook != -1 && *defcook != -1) ++ if (*refcook != -1 && *defcook != -1 && symname[0] != '\0') + fprintf (stderr, "la_symbind: %s %u\n", symname, + *flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ? 1 : 0); + return sym->st_value; +diff --git a/sysdeps/hppa/dl-lookupcfg.h b/sysdeps/hppa/dl-lookupcfg.h +index c3fea1fe5776b17a..86f6a04af46c87ba 100644 +--- a/sysdeps/hppa/dl-lookupcfg.h ++++ b/sysdeps/hppa/dl-lookupcfg.h +@@ -79,7 +79,9 @@ void attribute_hidden _dl_unmap (struct link_map *map); + /* Extract the code address from a fixup value */ + #define DL_FIXUP_VALUE_CODE_ADDR(value) ((value).ip) + #define DL_FIXUP_VALUE_ADDR(value) ((uintptr_t) &(value)) +-#define DL_FIXUP_ADDR_VALUE(addr) (*(struct fdesc *) (addr)) ++/* Clear the plabel bit to get the actual address of the descriptor. */ ++#define DL_FIXUP_ADDR_VALUE(addr) \ ++ (*(DL_FIXUP_VALUE_TYPE *) ((uintptr_t) (addr) & ~2)) + #define DL_FIXUP_BINDNOW_ADDR_VALUE(addr) (addr) +-#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ +- (*value) = *(struct fdesc *) (st_value) ++#define DL_FIXUP_BINDNOW_RELOC(value, new_value, st_value) \ ++ *(value) = *(DL_FIXUP_VALUE_TYPE *) ((uintptr_t) (new_value) & ~2) diff --git a/SOURCES/glibc-rh2047981-38.patch b/SOURCES/glibc-rh2047981-38.patch new file mode 100644 index 0000000..5e7b79f --- /dev/null +++ b/SOURCES/glibc-rh2047981-38.patch @@ -0,0 +1,44 @@ +commit bc02f1fa2fb302eb8a486794c6b7e4811229b81e +Author: Adhemerval Zanella +Date: Fri Mar 25 08:53:42 2022 -0300 + + elf: Remove unused functions from tst-audit25(a,b) + +diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c +index 49173e862516e876..c2cff8541b3741c3 100644 +--- a/elf/tst-audit25a.c ++++ b/elf/tst-audit25a.c +@@ -49,14 +49,6 @@ handle_restart (void) + return 0; + } + +-static inline bool +-startswith (const char *str, const char *pre) +-{ +- size_t lenpre = strlen (pre); +- size_t lenstr = strlen (str); +- return lenstr < lenpre ? false : memcmp (pre, str, lenpre) == 0; +-} +- + static int + do_test (int argc, char *argv[]) + { +diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c +index a56638d501f9bff5..46391770fdfc1796 100644 +--- a/elf/tst-audit25b.c ++++ b/elf/tst-audit25b.c +@@ -48,14 +48,6 @@ handle_restart (void) + return 0; + } + +-static inline bool +-startswith (const char *str, const char *pre) +-{ +- size_t lenpre = strlen (pre); +- size_t lenstr = strlen (str); +- return lenstr >= lenpre && memcmp (pre, str, lenpre) == 0; +-} +- + static int + do_test (int argc, char *argv[]) + { diff --git a/SOURCES/glibc-rh2047981-39.patch b/SOURCES/glibc-rh2047981-39.patch new file mode 100644 index 0000000..36247b1 --- /dev/null +++ b/SOURCES/glibc-rh2047981-39.patch @@ -0,0 +1,42 @@ +commit 5325233313c66aea13e86f5dd59618e9dd74b510 +Author: Stefan Liebler +Date: Thu Apr 7 13:59:48 2022 +0200 + + S390: Fix elf/tst-audit25[ab] + + If glibc is configured with --disable-default-pie and build on + s390 with -O3, the tests elf/tst-audit25a and elf/tst-audit25b are + failing as there are additional la_symbind lines for free and malloc. + It turns out that those belong to the executable. In fact those are + the PLT-stubs. Furthermore la_symbind is also called for calloc and + realloc symbols, but those belong to libc. + + Those functions are not called at all, but dlsym'ed in + elf/dl-minimal.c: + __rtld_malloc_init_real (struct link_map *main_map) + { + ... + void *new_calloc = lookup_malloc_symbol (main_map, "calloc", &version); + void *new_free = lookup_malloc_symbol (main_map, "free", &version); + void *new_malloc = lookup_malloc_symbol (main_map, "malloc", &version); + void *new_realloc = lookup_malloc_symbol (main_map, "realloc", &version); + ... + } + + Therefore, this commit just ignored symbols with LA_SYMB_DLSYM flag. + Reviewed-by: Adheemrval Zanella + +diff --git a/elf/tst-auditmod25.c b/elf/tst-auditmod25.c +index 20640a8daf346b5f..0524c5aab17fabba 100644 +--- a/elf/tst-auditmod25.c ++++ b/elf/tst-auditmod25.c +@@ -72,7 +72,8 @@ la_symbind32 (Elf32_Sym *sym, unsigned int ndx, + unsigned int *flags, const char *symname) + #endif + { +- if (*refcook != -1 && *defcook != -1 && symname[0] != '\0') ++ if (*refcook != -1 && *defcook != -1 && symname[0] != '\0' ++ && (*flags & LA_SYMB_DLSYM) == 0) + fprintf (stderr, "la_symbind: %s %u\n", symname, + *flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT) ? 1 : 0); + return sym->st_value; diff --git a/SOURCES/glibc-rh2047981-4.patch b/SOURCES/glibc-rh2047981-4.patch new file mode 100644 index 0000000..86468bd --- /dev/null +++ b/SOURCES/glibc-rh2047981-4.patch @@ -0,0 +1,34 @@ +commit 3ad5dab476205d6e16156cf0511fa6884b3b0fc4 +Author: Florian Weimer +Date: Tue Jul 7 09:58:45 2020 +0200 + + elf: Do not signal LA_ACT_CONSISTENT for an empty namespace [BZ #26076] + + The auditing interface identifies namespaces by their first loaded + module. Once the namespace is empty, it is no longer possible to signal + LA_ACT_CONSISTENT for it because the first loaded module is already gone + at that point. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 7fe91bdd9aaf694e..698bda929c0eab6c 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -795,8 +795,14 @@ _dl_close_worker (struct link_map *map, bool force) + if (__glibc_unlikely (do_audit)) + { + struct link_map *head = ns->_ns_loaded; +- /* Do not call the functions for any auditing object. */ +- if (head->l_auditing == 0) ++ /* If head is NULL, the namespace has become empty, and the ++ audit interface does not give us a way to signal ++ LA_ACT_CONSISTENT for it because the first loaded module is ++ used to identify the namespace. ++ ++ Furthermore, do not notify auditors of the cleanup of a ++ failed audit module loading attempt. */ ++ if (head != NULL && head->l_auditing == 0) + { + struct audit_ifaces *afct = GLRO(dl_audit); + for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) diff --git a/SOURCES/glibc-rh2047981-40.patch b/SOURCES/glibc-rh2047981-40.patch new file mode 100644 index 0000000..f1f4e80 --- /dev/null +++ b/SOURCES/glibc-rh2047981-40.patch @@ -0,0 +1,170 @@ +commit e4a2fb76efb45210c541ee3f8ef32f317783c3a8 +Author: Florian Weimer +Date: Wed May 11 20:30:49 2022 +0200 + + manual: Document the dlinfo function + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + (cherry picked from commit 93804a1ee084d4bdc620b2b9f91615c7da0fabe1) + + Also includes partial backport of commit 5d28a8962dcb6ec056b81d730e + (the addition of manual/dynlink.texi). + +diff --git a/manual/Makefile b/manual/Makefile +index c2756640a785afe1..4c835e568f3bab67 100644 +--- a/manual/Makefile ++++ b/manual/Makefile +@@ -39,7 +39,7 @@ chapters = $(addsuffix .texi, \ + pipe socket terminal syslog math arith time \ + resource setjmp signal startup process ipc job \ + nss users sysinfo conf crypt debug threads \ +- probes tunables) ++ dynlink probes tunables) + appendices = lang.texi header.texi install.texi maint.texi platform.texi \ + contrib.texi + licenses = freemanuals.texi lgpl-2.1.texi fdl-1.3.texi +diff --git a/manual/dynlink.texi b/manual/dynlink.texi +new file mode 100644 +index 0000000000000000..dbf3de11769d8e57 +--- /dev/null ++++ b/manual/dynlink.texi +@@ -0,0 +1,100 @@ ++@node Dynamic Linker ++@c @node Dynamic Linker, Internal Probes, Threads, Top ++@c %MENU% Loading programs and shared objects. ++@chapter Dynamic Linker ++@cindex dynamic linker ++@cindex dynamic loader ++ ++The @dfn{dynamic linker} is responsible for loading dynamically linked ++programs and their dependencies (in the form of shared objects). The ++dynamic linker in @theglibc{} also supports loading shared objects (such ++as plugins) later at run time. ++ ++Dynamic linkers are sometimes called @dfn{dynamic loaders}. ++ ++@menu ++* Dynamic Linker Introspection:: Interfaces for querying mapping information. ++@end menu ++ ++@node Dynamic Linker Introspection ++@section Dynamic Linker Introspection ++ ++@Theglibc{} provides various functions for querying information from the ++dynamic linker. ++ ++@deftypefun {int} dlinfo (void *@var{handle}, int @var{request}, void *@var{arg}) ++@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} ++@standards{GNU, dlfcn.h} ++This function returns information about @var{handle} in the memory ++location @var{arg}, based on @var{request}. The @var{handle} argument ++must be a pointer returned by @code{dlopen} or @code{dlmopen}; it must ++not have been closed by @code{dlclose}. ++ ++On success, @code{dlinfo} returns 0. If there is an error, the function ++returns @math{-1}, and @code{dlerror} can be used to obtain a ++corresponding error message. ++ ++The following operations are defined for use with @var{request}: ++ ++@vtable @code ++@item RTLD_DI_LINKMAP ++The corresponding @code{struct link_map} pointer for @var{handle} is ++written to @code{*@var{arg}}. The @var{arg} argument must be the ++address of an object of type @code{struct link_map *}. ++ ++@item RTLD_DI_LMID ++The namespace identifier of @var{handle} is written to ++@code{*@var{arg}}. The @var{arg} argument must be the address of an ++object of type @code{Lmid_t}. ++ ++@item RTLD_DI_ORIGIN ++The value of the @code{$ORIGIN} dynamic string token for @var{handle} is ++written to the character array starting at @var{arg} as a ++null-terminated string. ++ ++This request type should not be used because it is prone to buffer ++overflows. ++ ++@item RTLD_DI_SERINFO ++@itemx RTLD_DI_SERINFOSIZE ++These requests can be used to obtain search path information for ++@var{handle}. For both requests, @var{arg} must point to a ++@code{Dl_serinfo} object. The @code{RTLD_DI_SERINFOSIZE} request must ++be made first; it updates the @code{dls_size} and @code{dls_cnt} members ++of the @code{Dl_serinfo} object. The caller should then allocate memory ++to store at least @code{dls_size} bytes and pass that buffer to a ++@code{RTLD_DI_SERINFO} request. This second request fills the ++@code{dls_serpath} array. The number of array elements was returned in ++the @code{dls_cnt} member in the initial @code{RTLD_DI_SERINFOSIZE} ++request. The caller is responsible for freeing the allocated buffer. ++ ++This interface is prone to buffer overflows in multi-threaded processes ++because the required size can change between the ++@code{RTLD_DI_SERINFOSIZE} and @code{RTLD_DI_SERINFO} requests. ++ ++@item RTLD_DI_TLS_DATA ++This request writes the address of the TLS block (in the current thread) ++for the shared object identified by @var{handle} to @code{*@var{arg}}. ++The argument @var{arg} must be the address of an object of type ++@code{void *}. A null pointer is written if the object does not have ++any associated TLS block. ++ ++@item RTLD_DI_TLS_MODID ++This request writes the TLS module ID for the shared object @var{handle} ++to @code{*@var{arg}}. The argument @var{arg} must be the address of an ++object of type @code{size_t}. The module ID is zero if the object ++does not have an associated TLS block. ++@end vtable ++ ++The @code{dlinfo} function is a GNU extension. ++@end deftypefun ++ ++@c FIXME these are undocumented: ++@c dladdr ++@c dladdr1 ++@c dlclose ++@c dlerror ++@c dlmopen ++@c dlopen ++@c dlsym ++@c dlvsym +diff --git a/manual/libdl.texi b/manual/libdl.texi +deleted file mode 100644 +index e3fe0452d9f41d47..0000000000000000 +--- a/manual/libdl.texi ++++ /dev/null +@@ -1,10 +0,0 @@ +-@c FIXME these are undocumented: +-@c dladdr +-@c dladdr1 +-@c dlclose +-@c dlerror +-@c dlinfo +-@c dlmopen +-@c dlopen +-@c dlsym +-@c dlvsym +diff --git a/manual/probes.texi b/manual/probes.texi +index 0ea560ed78bcfd7e..892d2451938eb379 100644 +--- a/manual/probes.texi ++++ b/manual/probes.texi +@@ -1,5 +1,5 @@ + @node Internal Probes +-@c @node Internal Probes, Tunables, Threads, Top ++@c @node Internal Probes, Tunables, Dynamic Linker, Top + @c %MENU% Probes to monitor libc internal behavior + @chapter Internal probes + +diff --git a/manual/threads.texi b/manual/threads.texi +index 87fda7d8e716e08c..1c26c57540746e3b 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -1,5 +1,5 @@ + @node Threads +-@c @node Threads, Internal Probes, Debugging Support, Top ++@c @node Threads, Dynamic Linker, Debugging Support, Top + @c %MENU% Functions, constants, and data types for working with threads + @chapter Threads + @cindex threads diff --git a/SOURCES/glibc-rh2047981-41.patch b/SOURCES/glibc-rh2047981-41.patch new file mode 100644 index 0000000..a92e82d --- /dev/null +++ b/SOURCES/glibc-rh2047981-41.patch @@ -0,0 +1,268 @@ +Added $(objpfx)tst-dlinfo-phdr: $(libdl) to dlfcn/Makefile since +we still need $(libdl) in RHEL8. + +commit d056c212130280c0a54d9a4f72170ec621b70ce5 +Author: Florian Weimer +Date: Fri Apr 29 17:00:53 2022 +0200 + + dlfcn: Implement the RTLD_DI_PHDR request type for dlinfo + + The information is theoretically available via dl_iterate_phdr as + well, but that approach is very slow if there are many shared + objects. + + Reviewed-by: Carlos O'Donell + Tested-by: Carlos O'Donell + +Conflicts: + dlfcn/dlinfo.c + (missing move into libc) + +diff --git a/dlfcn/Makefile b/dlfcn/Makefile +index 0b213b7d9fefcdc9..65cee5b54d891a24 100644 +--- a/dlfcn/Makefile ++++ b/dlfcn/Makefile +@@ -59,6 +59,10 @@ tststatic3-ENV = $(tststatic-ENV) + tststatic4-ENV = $(tststatic-ENV) + tststatic5-ENV = $(tststatic-ENV) + ++tests-internal += \ ++ tst-dlinfo-phdr \ ++ # tests-internal ++ + ifneq (,$(CXX)) + modules-names += bug-atexit3-lib + else +@@ -152,3 +156,5 @@ $(objpfx)bug-dl-leaf-lib-cb.so: $(objpfx)bug-dl-leaf-lib.so + + $(objpfx)tst-rec-dlopen: $(libdl) + $(objpfx)tst-rec-dlopen.out: $(objpfx)moddummy1.so $(objpfx)moddummy2.so ++ ++$(objpfx)tst-dlinfo-phdr: $(libdl) +diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h +index 0921fd724cf7b785..61c4f59bea4eb7ac 100644 +--- a/dlfcn/dlfcn.h ++++ b/dlfcn/dlfcn.h +@@ -162,7 +162,12 @@ enum + segment, or if the calling thread has not allocated a block for it. */ + RTLD_DI_TLS_DATA = 10, + +- RTLD_DI_MAX = 10 ++ /* Treat ARG as const ElfW(Phdr) **, and store the address of the ++ program header array at that location. The dlinfo call returns ++ the number of program headers in the array. */ ++ RTLD_DI_PHDR = 11, ++ ++ RTLD_DI_MAX = 11 + }; + + +diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c +index 23ef3f57ca41afdf..50cd9af17a56f990 100644 +--- a/dlfcn/dlinfo.c ++++ b/dlfcn/dlinfo.c +@@ -38,6 +38,10 @@ struct dlinfo_args + void *handle; + int request; + void *arg; ++ ++ /* This is the value that is returned from dlinfo if no error is ++ signaled. */ ++ int result; + }; + + static void +@@ -50,6 +54,7 @@ dlinfo_doit (void *argsblock) + { + case RTLD_DI_CONFIGADDR: + default: ++ args->result = -1; + _dl_signal_error (0, NULL, NULL, N_("unsupported dlinfo request")); + break; + +@@ -85,6 +90,11 @@ dlinfo_doit (void *argsblock) + *(void **) args->arg = data; + break; + } ++ ++ case RTLD_DI_PHDR: ++ *(const ElfW(Phdr) **) args->arg = l->l_phdr; ++ args->result = l->l_phnum; ++ break; + } + } + +@@ -97,7 +107,8 @@ __dlinfo (void *handle, int request, void *arg) + # endif + + struct dlinfo_args args = { handle, request, arg }; +- return _dlerror_run (&dlinfo_doit, &args) ? -1 : 0; ++ _dlerror_run (&dlinfo_doit, &args); ++ return args.result; + } + # ifdef SHARED + strong_alias (__dlinfo, dlinfo) +diff --git a/dlfcn/tst-dlinfo-phdr.c b/dlfcn/tst-dlinfo-phdr.c +new file mode 100644 +index 0000000000000000..a15a7d48ebd3b976 +--- /dev/null ++++ b/dlfcn/tst-dlinfo-phdr.c +@@ -0,0 +1,125 @@ ++/* Test for dlinfo (RTLD_DI_PHDR). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* Used to verify that the program header array appears as expected ++ among the dl_iterate_phdr callback invocations. */ ++ ++struct dlip_callback_args ++{ ++ struct link_map *l; /* l->l_addr is used to find the object. */ ++ const ElfW(Phdr) *phdr; /* Expected program header pointed. */ ++ int phnum; /* Expected program header count. */ ++ bool found; /* True if l->l_addr has been found. */ ++}; ++ ++static int ++dlip_callback (struct dl_phdr_info *dlpi, size_t size, void *closure) ++{ ++ TEST_COMPARE (sizeof (*dlpi), size); ++ struct dlip_callback_args *args = closure; ++ ++ if (dlpi->dlpi_addr == args->l->l_addr) ++ { ++ TEST_VERIFY (!args->found); ++ args->found = true; ++ TEST_VERIFY (args->phdr == dlpi->dlpi_phdr); ++ TEST_COMPARE (args->phnum, dlpi->dlpi_phnum); ++ } ++ ++ return 0; ++} ++ ++static int ++do_test (void) ++{ ++ /* Avoid a copy relocation. */ ++ struct r_debug *debug = xdlsym (RTLD_DEFAULT, "_r_debug"); ++ struct link_map *l = (struct link_map *) debug->r_map; ++ TEST_VERIFY_EXIT (l != NULL); ++ ++ do ++ { ++ printf ("info: checking link map %p (%p) for \"%s\"\n", ++ l, l->l_phdr, l->l_name); ++ ++ /* Cause dlerror () to return an error message. */ ++ dlsym (RTLD_DEFAULT, "does-not-exist"); ++ ++ /* Use the extension that link maps are valid dlopen handles. */ ++ const ElfW(Phdr) *phdr; ++ int phnum = dlinfo (l, RTLD_DI_PHDR, &phdr); ++ TEST_VERIFY (phnum >= 0); ++ /* Verify that the error message has been cleared. */ ++ TEST_COMPARE_STRING (dlerror (), NULL); ++ ++ TEST_VERIFY (phdr == l->l_phdr); ++ TEST_COMPARE (phnum, l->l_phnum); ++ ++ /* Check that we can find PT_DYNAMIC among the array. */ ++ { ++ bool dynamic_found = false; ++ for (int i = 0; i < phnum; ++i) ++ if (phdr[i].p_type == PT_DYNAMIC) ++ { ++ dynamic_found = true; ++ TEST_COMPARE ((ElfW(Addr)) l->l_ld, l->l_addr + phdr[i].p_vaddr); ++ } ++ TEST_VERIFY (dynamic_found); ++ } ++ ++ /* Check that dl_iterate_phdr finds the link map with the same ++ program headers. */ ++ { ++ struct dlip_callback_args args = ++ { ++ .l = l, ++ .phdr = phdr, ++ .phnum = phnum, ++ .found = false, ++ }; ++ TEST_COMPARE (dl_iterate_phdr (dlip_callback, &args), 0); ++ TEST_VERIFY (args.found); ++ } ++ ++ if (l->l_prev == NULL) ++ { ++ /* This is the executable, so the information is also ++ available via getauxval. */ ++ TEST_COMPARE_STRING (l->l_name, ""); ++ TEST_VERIFY (phdr == (const ElfW(Phdr) *) getauxval (AT_PHDR)); ++ TEST_COMPARE (phnum, getauxval (AT_PHNUM)); ++ } ++ ++ l = l->l_next; ++ } ++ while (l != NULL); ++ ++ return 0; ++} ++ ++#include +diff --git a/manual/dynlink.texi b/manual/dynlink.texi +index dbf3de11769d8e57..7dcac64889e389fd 100644 +--- a/manual/dynlink.texi ++++ b/manual/dynlink.texi +@@ -30,9 +30,9 @@ location @var{arg}, based on @var{request}. The @var{handle} argument + must be a pointer returned by @code{dlopen} or @code{dlmopen}; it must + not have been closed by @code{dlclose}. + +-On success, @code{dlinfo} returns 0. If there is an error, the function +-returns @math{-1}, and @code{dlerror} can be used to obtain a +-corresponding error message. ++On success, @code{dlinfo} returns 0 for most request types; exceptions ++are noted below. If there is an error, the function returns @math{-1}, ++and @code{dlerror} can be used to obtain a corresponding error message. + + The following operations are defined for use with @var{request}: + +@@ -84,6 +84,15 @@ This request writes the TLS module ID for the shared object @var{handle} + to @code{*@var{arg}}. The argument @var{arg} must be the address of an + object of type @code{size_t}. The module ID is zero if the object + does not have an associated TLS block. ++ ++@item RTLD_DI_PHDR ++This request writes the address of the program header array to ++@code{*@var{arg}}. The argument @var{arg} must be the address of an ++object of type @code{const ElfW(Phdr) *} (that is, ++@code{const Elf32_Phdr *} or @code{const Elf64_Phdr *}, as appropriate ++for the current architecture). For this request, the value returned by ++@code{dlinfo} is the number of program headers in the program header ++array. + @end vtable + + The @code{dlinfo} function is a GNU extension. diff --git a/SOURCES/glibc-rh2047981-42.patch b/SOURCES/glibc-rh2047981-42.patch new file mode 100644 index 0000000..d280e1a --- /dev/null +++ b/SOURCES/glibc-rh2047981-42.patch @@ -0,0 +1,296 @@ +commit ad43cac44a6860eaefcadadfb2acb349921e96bf +Author: Szabolcs Nagy +Date: Fri Jun 15 16:14:58 2018 +0100 + + rtld: Use generic argv adjustment in ld.so [BZ #23293] + + When an executable is invoked as + + ./ld.so [ld.so-args] ./exe [exe-args] + + then the argv is adujusted in ld.so before calling the entry point of + the executable so ld.so args are not visible to it. On most targets + this requires moving argv, env and auxv on the stack to ensure correct + stack alignment at the entry point. This had several issues: + + - The code for this adjustment on the stack is written in asm as part + of the target specific ld.so _start code which is hard to maintain. + + - The adjustment is done after _dl_start returns, where it's too late + to update GLRO(dl_auxv), as it is already readonly, so it points to + memory that was clobbered by the adjustment. This is bug 23293. + + - _environ is also wrong in ld.so after the adjustment, but it is + likely not used after _dl_start returns so this is not user visible. + + - _dl_argv was updated, but for this it was moved out of relro, which + changes security properties across targets unnecessarily. + + This patch introduces a generic _dl_start_args_adjust function that + handles the argument adjustments after ld.so processed its own args + and before relro protection is applied. + + The same algorithm is used on all targets, _dl_skip_args is now 0, so + existing target specific adjustment code is no longer used. The bug + affects aarch64, alpha, arc, arm, csky, ia64, nios2, s390-32 and sparc, + other targets don't need the change in principle, only for consistency. + + The GNU Hurd start code relied on _dl_skip_args after dl_main returned, + now it checks directly if args were adjusted and fixes the Hurd startup + data accordingly. + + Follow up patches can remove _dl_skip_args and DL_ARGV_NOT_RELRO. + + Tested on aarch64-linux-gnu and cross tested on i686-gnu. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/rtld.c b/elf/rtld.c +index aee5ca357f66121e..22cceeab40319582 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1127,6 +1127,62 @@ rtld_chain_load (struct link_map *main_map, char *argv0) + rtld_soname, pathname, errcode); + } + ++/* Adjusts the contents of the stack and related globals for the user ++ entry point. The ld.so processed skip_args arguments and bumped ++ _dl_argv and _dl_argc accordingly. Those arguments are removed from ++ argv here. */ ++static void ++_dl_start_args_adjust (int skip_args) ++{ ++ void **sp = (void **) (_dl_argv - skip_args - 1); ++ void **p = sp + skip_args; ++ ++ if (skip_args == 0) ++ return; ++ ++ /* Sanity check. */ ++ intptr_t argc = (intptr_t) sp[0] - skip_args; ++ assert (argc == _dl_argc); ++ ++ /* Adjust argc on stack. */ ++ sp[0] = (void *) (intptr_t) _dl_argc; ++ ++ /* Update globals in rtld. */ ++ _dl_argv -= skip_args; ++ _environ -= skip_args; ++ ++ /* Shuffle argv down. */ ++ do ++ *++sp = *++p; ++ while (*p != NULL); ++ ++ assert (_environ == (char **) (sp + 1)); ++ ++ /* Shuffle envp down. */ ++ do ++ *++sp = *++p; ++ while (*p != NULL); ++ ++#ifdef HAVE_AUX_VECTOR ++ void **auxv = (void **) GLRO(dl_auxv) - skip_args; ++ GLRO(dl_auxv) = (ElfW(auxv_t) *) auxv; /* Aliasing violation. */ ++ assert (auxv == sp + 1); ++ ++ /* Shuffle auxv down. */ ++ ElfW(auxv_t) ax; ++ char *oldp = (char *) (p + 1); ++ char *newp = (char *) (sp + 1); ++ do ++ { ++ memcpy (&ax, oldp, sizeof (ax)); ++ memcpy (newp, &ax, sizeof (ax)); ++ oldp += sizeof (ax); ++ newp += sizeof (ax); ++ } ++ while (ax.a_type != AT_NULL); ++#endif ++} ++ + static void + dl_main (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, +@@ -1185,6 +1241,7 @@ dl_main (const ElfW(Phdr) *phdr, + rtld_is_main = true; + + char *argv0 = NULL; ++ char **orig_argv = _dl_argv; + + /* Note the place where the dynamic linker actually came from. */ + GL(dl_rtld_map).l_name = rtld_progname; +@@ -1199,7 +1256,6 @@ dl_main (const ElfW(Phdr) *phdr, + GLRO(dl_lazy) = -1; + } + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } +@@ -1208,14 +1264,12 @@ dl_main (const ElfW(Phdr) *phdr, + if (state.mode != rtld_mode_help) + state.mode = rtld_mode_verify; + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } + else if (! strcmp (_dl_argv[1], "--inhibit-cache")) + { + GLRO(dl_inhibit_cache) = 1; +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } +@@ -1225,7 +1279,6 @@ dl_main (const ElfW(Phdr) *phdr, + state.library_path = _dl_argv[2]; + state.library_path_source = "--library-path"; + +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1234,7 +1287,6 @@ dl_main (const ElfW(Phdr) *phdr, + { + GLRO(dl_inhibit_rpath) = _dl_argv[2]; + +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1242,14 +1294,12 @@ dl_main (const ElfW(Phdr) *phdr, + { + audit_list_add_string (&state.audit_list, _dl_argv[2]); + +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } + else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2) + { + state.preloadarg = _dl_argv[2]; +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1257,7 +1307,6 @@ dl_main (const ElfW(Phdr) *phdr, + { + argv0 = _dl_argv[2]; + +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1265,7 +1314,6 @@ dl_main (const ElfW(Phdr) *phdr, + && _dl_argc > 2) + { + state.glibc_hwcaps_prepend = _dl_argv[2]; +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1273,7 +1321,6 @@ dl_main (const ElfW(Phdr) *phdr, + && _dl_argc > 2) + { + state.glibc_hwcaps_mask = _dl_argv[2]; +- _dl_skip_args += 2; + _dl_argc -= 2; + _dl_argv += 2; + } +@@ -1282,7 +1329,6 @@ dl_main (const ElfW(Phdr) *phdr, + { + state.mode = rtld_mode_list_tunables; + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } +@@ -1291,7 +1337,6 @@ dl_main (const ElfW(Phdr) *phdr, + { + state.mode = rtld_mode_list_diagnostics; + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + } +@@ -1337,7 +1382,6 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_usage (ld_so_name, NULL); + } + +- ++_dl_skip_args; + --_dl_argc; + ++_dl_argv; + +@@ -1433,6 +1477,9 @@ dl_main (const ElfW(Phdr) *phdr, + /* Set the argv[0] string now that we've processed the executable. */ + if (argv0 != NULL) + _dl_argv[0] = argv0; ++ ++ /* Adjust arguments for the application entry point. */ ++ _dl_start_args_adjust (_dl_argv - orig_argv); + } + else + { +diff --git a/sysdeps/mach/hurd/dl-sysdep.c b/sysdeps/mach/hurd/dl-sysdep.c +index 7bd1d70c96c229e0..8aab46bf6396c8d4 100644 +--- a/sysdeps/mach/hurd/dl-sysdep.c ++++ b/sysdeps/mach/hurd/dl-sysdep.c +@@ -107,6 +107,7 @@ _dl_sysdep_start (void **start_argptr, + { + void go (intptr_t *argdata) + { ++ char *orig_argv0; + char **p; + + /* Cache the information in various global variables. */ +@@ -115,6 +116,8 @@ _dl_sysdep_start (void **start_argptr, + _environ = &_dl_argv[_dl_argc + 1]; + for (p = _environ; *p++;); /* Skip environ pointers and terminator. */ + ++ orig_argv0 = _dl_argv[0]; ++ + if ((void *) p == _dl_argv[0]) + { + static struct hurd_startup_data nodata; +@@ -189,30 +192,23 @@ unfmh(); /* XXX */ + + /* The call above might screw a few things up. + +- First of all, if _dl_skip_args is nonzero, we are ignoring +- the first few arguments. However, if we have no Hurd startup +- data, it is the magical convention that ARGV[0] == P. The ++ P is the location after the terminating NULL of the list of ++ environment variables. It has to point to the Hurd startup ++ data or if that's missing then P == ARGV[0] must hold. The + startup code in init-first.c will get confused if this is not + the case, so we must rearrange things to make it so. We'll +- overwrite the origional ARGV[0] at P with ARGV[_dl_skip_args]. ++ recompute P and move the Hurd data or the new ARGV[0] there. + +- Secondly, if we need to be secure, it removes some dangerous +- environment variables. If we have no Hurd startup date this +- changes P (since that's the location after the terminating +- NULL in the list of environment variables). We do the same +- thing as in the first case but make sure we recalculate P. +- If we do have Hurd startup data, we have to move the data +- such that it starts just after the terminating NULL in the +- environment list. ++ Note: directly invoked ld.so can move arguments and env vars. + + We use memmove, since the locations might overlap. */ +- if (__libc_enable_secure || _dl_skip_args) +- { +- char **newp; + +- for (newp = _environ; *newp++;); ++ char **newp; ++ for (newp = _environ; *newp++;); + +- if (_dl_argv[-_dl_skip_args] == (char *) p) ++ if (newp != p || _dl_argv[0] != orig_argv0) ++ { ++ if (orig_argv0 == (char *) p) + { + if ((char *) newp != _dl_argv[0]) + { diff --git a/SOURCES/glibc-rh2047981-43.patch b/SOURCES/glibc-rh2047981-43.patch new file mode 100644 index 0000000..13691c9 --- /dev/null +++ b/SOURCES/glibc-rh2047981-43.patch @@ -0,0 +1,22 @@ +commit 62c888b3375f82a659a55ec66b1315efa2ed026a +Author: Carlos O'Donell +Date: Thu Jun 2 10:59:14 2022 -0400 + + elf: Add #include for MAX usage. + + In _dl_audit_pltenter we use MAX and so need to include param.h. + + Tested on x86_64 and i686 without regression. + +diff --git a/elf/dl-audit.c b/elf/dl-audit.c +index ec9b032eae37c103..e20b7b40e08d79e7 100644 +--- a/elf/dl-audit.c ++++ b/elf/dl-audit.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + void + _dl_audit_activity_map (struct link_map *l, int action) diff --git a/SOURCES/glibc-rh2047981-44.patch b/SOURCES/glibc-rh2047981-44.patch new file mode 100644 index 0000000..e5f9389 --- /dev/null +++ b/SOURCES/glibc-rh2047981-44.patch @@ -0,0 +1,98 @@ +Downstream-only patch to change rtld_active () to return true during +early audit operations. GLRO (_dl_profile_output) is initialized much +earlier than GLRO (dl_init_all_dirs), before auditors run, so it is a +good replacement. + +This is addressed downstream very differently, in this commit: + +commit 8dcb6d0af07fda3607b541857e4f3970a74ed55b +Author: Florian Weimer +Date: Tue Apr 26 14:23:02 2022 +0200 + + dlfcn: Do not use rtld_active () to determine ld.so state (bug 29078) + + When audit modules are loaded, ld.so initialization is not yet + complete, and rtld_active () returns false even though ld.so is + mostly working. Instead, the static dlopen hook is used, but that + does not work at all because this is not a static dlopen situation. + + Commit 466c1ea15f461edb8e3ffaf5d86d708876343bbf ("dlfcn: Rework + static dlopen hooks") moved the hook pointer into _rtld_global_ro, + which means that separate protection is not needed anymore and the + hook pointer can be checked directly. + + The guard for disabling libio vtable hardening in _IO_vtable_check + should stay for now. + + Fixes commit 8e1472d2c1e25e6eabc2059170731365f6d5b3d1 ("ld.so: + Examine GLRO to detect inactive loader [BZ #20204]"). + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/rtld.c b/elf/rtld.c +index 22cceeab40319582..b47e84ca2fb6f03c 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2352,9 +2352,7 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist; + + /* Remember the last search directory added at startup, now that +- malloc will no longer be the one from dl-minimal.c. As a side +- effect, this marks ld.so as initialized, so that the rtld_active +- function returns true from now on. */ ++ malloc will no longer be the one from dl-minimal.c. */ + GLRO(dl_init_all_dirs) = GL(dl_all_dirs); + + /* Print scope information. */ +@@ -2675,7 +2673,9 @@ process_envvars (struct dl_main_state *state) + char *envline; + char *debug_output = NULL; + +- /* This is the default place for profiling data file. */ ++ /* This is the default place for profiling data file. As a side ++ effect, this marks ld.so as initialized, so that the rtld_active ++ function returns true from now on. */ + GLRO(dl_profile_output) + = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0]; + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index d4f70211c34d1c59..9dec9e3d3b6d6aa2 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -600,18 +600,18 @@ struct rtld_global_ro + + /* Name of the shared object to be profiled (if any). */ + EXTERN const char *_dl_profile; +- /* Filename of the output file. */ ++ /* Filename of the output file. This is assigned a ++ non-NULL pointer by the ld.so startup code (after initialization ++ to NULL), so this can also serve as an indicator whether a copy ++ of ld.so is initialized and active. See the rtld_active function ++ below. */ + EXTERN const char *_dl_profile_output; + /* Name of the object we want to trace the prelinking. */ + EXTERN const char *_dl_trace_prelink; + /* Map of shared object to be prelink traced. */ + EXTERN struct link_map *_dl_trace_prelink_map; + +- /* All search directories defined at startup. This is assigned a +- non-NULL pointer by the ld.so startup code (after initialization +- to NULL), so this can also serve as an indicator whether a copy +- of ld.so is initialized and active. See the rtld_active function +- below. */ ++ /* All search directories defined at startup. */ + EXTERN struct r_search_path_elem *_dl_init_all_dirs; + + #ifdef NEED_DL_SYSINFO +@@ -1259,9 +1259,9 @@ static inline bool + rtld_active (void) + { + /* The default-initialized variable does not have a non-zero +- dl_init_all_dirs member, so this allows us to recognize an ++ dl_profile_output member, so this allows us to recognize an + initialized and active ld.so copy. */ +- return GLRO(dl_init_all_dirs) != NULL; ++ return GLRO(dl_profile_output) != NULL; + } + + static inline struct auditstate * diff --git a/SOURCES/glibc-rh2047981-45.patch b/SOURCES/glibc-rh2047981-45.patch new file mode 100644 index 0000000..0111ab9 --- /dev/null +++ b/SOURCES/glibc-rh2047981-45.patch @@ -0,0 +1,74 @@ +commit a64af8c9b6598f6d2685227f64f5ccb9b48c663c +Author: Florian Weimer +Date: Mon May 10 10:31:41 2021 +0200 + + scripts/versions.awk: Add strings and hashes to + + This generates new macros of this from: + + They are useful for symbol lookups using _dl_lookup_direct. + + Tested-by: Carlos O'Donell + Reviewed-by: Carlos O'Donell + +diff --git a/scripts/versions.awk b/scripts/versions.awk +index a3df316c703ea98b..0c900b83347ce8f9 100644 +--- a/scripts/versions.awk ++++ b/scripts/versions.awk +@@ -32,6 +32,29 @@ BEGIN { + sort = "sort -t. -k 1,1 -k 2n,2n -k 3 > " tmpfile; + } + ++# GNU awk does not implement the ord and chr functions. ++# ++# says that they are "written very nicely", using code similar to what ++# is included here. ++function chr(c) { ++ return sprintf("%c", c) ++} ++ ++BEGIN { ++ for (c = 1; c < 127; c++) { ++ ord_table[chr(c)] = c; ++ } ++} ++ ++function ord(c) { ++ if (ord_table[c]) { ++ return ord_table[c]; ++ } else { ++ printf("Invalid character reference: '%c'\n", c) > "/dev/stderr"; ++ ++lossage; ++ } ++} ++ + # Remove comment lines. + /^ *#/ { + next; +@@ -90,6 +113,17 @@ function close_and_move(name, real_name) { + system(move_if_change " " name " " real_name " >&2"); + } + ++# ELF hash, for use with symbol versions. ++function elf_hash(s, i, acc) { ++ acc = 0; ++ for (i = 1; i <= length(s); ++i) { ++ acc = and(lshift(acc, 4) + ord(substr(s, i, 1)), 0xffffffff); ++ top = and(acc, 0xf0000000); ++ acc = and(xor(acc, rshift(top, 24)), compl(top)); ++ } ++ return acc; ++} ++ + # Now print the accumulated information. + END { + close(sort); +@@ -145,6 +179,8 @@ END { + && oldver ~ "^GLIBC_[0-9]" \ + && sym ~ "^[A-Za-z0-9_]*$") { + ver_val = oldver; ++ printf("#define %s_STRING \"%s\"\n", first_ver_macro, ver_val) > first_ver_header; ++ printf("#define %s_HASH 0x%x\n", first_ver_macro, elf_hash(ver_val)) > first_ver_header; + gsub("\\.", "_", ver_val); + printf("#define %s %s\n", first_ver_macro, ver_val) > first_ver_header; + first_ver_seen[first_ver_macro] = 1; diff --git a/SOURCES/glibc-rh2047981-46.patch b/SOURCES/glibc-rh2047981-46.patch new file mode 100644 index 0000000..3bbd90a --- /dev/null +++ b/SOURCES/glibc-rh2047981-46.patch @@ -0,0 +1,227 @@ +Backport of the new test from this upstream commit: + +commit 8dcb6d0af07fda3607b541857e4f3970a74ed55b +Author: Florian Weimer +Date: Tue Apr 26 14:23:02 2022 +0200 + + dlfcn: Do not use rtld_active () to determine ld.so state (bug 29078) + + When audit modules are loaded, ld.so initialization is not yet + complete, and rtld_active () returns false even though ld.so is + mostly working. Instead, the static dlopen hook is used, but that + does not work at all because this is not a static dlopen situation. + + Commit 466c1ea15f461edb8e3ffaf5d86d708876343bbf ("dlfcn: Rework + static dlopen hooks") moved the hook pointer into _rtld_global_ro, + which means that separate protection is not needed anymore and the + hook pointer can be checked directly. + + The guard for disabling libio vtable hardening in _IO_vtable_check + should stay for now. + + Fixes commit 8e1472d2c1e25e6eabc2059170731365f6d5b3d1 ("ld.so: + Examine GLRO to detect inactive loader [BZ #20204]"). + + Reviewed-by: Adhemerval Zanella + +Conflicts: + dlfcn/dladdr.c + dlfcn/dladdr1.c + dlfcn/dlclose.c + dlfcn/dlerror.c + dlfcn/dlinfo.c + dlfcn/dlmopen.c + dlfcn/dlopen.c + dlfcn/dlopenold.c + dlfcn/dlsym.c + dlfcn/dlvsym.c + elf/dl-libc.c + (Code changes not needed.) + elf/Makefile + (Usual test list conflicts. Also added $(libdl).) + +diff --git a/elf/Makefile b/elf/Makefile +index 6d39b400060a73f3..3fae27d32676caf9 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -353,8 +353,7 @@ tests += \ + tst-audit24d \ + tst-audit25a \ + tst-audit25b \ +- tst-audit8 \ +- tst-audit9 \ ++ tst-audit26 \ + tst-auditmany \ + tst-auxobj \ + tst-auxobj-dlopen \ +@@ -659,6 +658,7 @@ modules-names = \ + tst-auditmod24c \ + tst-auditmod24d \ + tst-auditmod25 \ ++ tst-auditmod26 \ + tst-big-note-lib \ + tst-deep1mod1 \ + tst-deep1mod2 \ +@@ -2145,6 +2145,11 @@ $(objpfx)tst-audit25b: $(objpfx)tst-audit25mod1.so \ + LDFLAGS-tst-audit25b = -Wl,-z,now + tst-audit25b-ARGS = -- $(host-test-program-cmd) + ++$(objpfx)tst-audit26: $(libdl) ++$(objpfx)tst-audit26.out: $(objpfx)tst-auditmod26.so ++$(objpfx)tst-auditmod26.so: $(libsupport) $(libdl) ++tst-audit26-ENV = LD_AUDIT=$(objpfx)tst-auditmod26.so ++ + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ + -Wl,--version-script=tst-sonamemove-linkmod1.map \ +diff --git a/elf/tst-audit26.c b/elf/tst-audit26.c +new file mode 100644 +index 0000000000000000..3f920e83bac247a5 +--- /dev/null ++++ b/elf/tst-audit26.c +@@ -0,0 +1,35 @@ ++/* Check the usability of functions in audit modules. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Check that the audit module has been loaded. */ ++ void *handle = xdlopen ("mapped to libc", RTLD_LOCAL | RTLD_NOW); ++ TEST_VERIFY (handle ++ == xdlopen (LIBC_SO, RTLD_LOCAL | RTLD_NOW | RTLD_NOLOAD)); ++ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-auditmod26.c b/elf/tst-auditmod26.c +new file mode 100644 +index 0000000000000000..db7ba95abec20f53 +--- /dev/null ++++ b/elf/tst-auditmod26.c +@@ -0,0 +1,104 @@ ++/* Check the usability of functions in audit modules. Audit module. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++unsigned int ++la_version (unsigned int current) ++{ ++ /* Exercise various functions. */ ++ ++ /* Check dlopen, dlsym, dlclose. */ ++ void *handle = xdlopen (LIBM_SO, RTLD_LOCAL | RTLD_NOW); ++ void *ptr = xdlsym (handle, "sincos"); ++ TEST_VERIFY (ptr != NULL); ++ ptr = dlsym (handle, "SINCOS"); ++ TEST_VERIFY (ptr == NULL); ++ const char *message = dlerror (); ++ TEST_VERIFY (strstr (message, ": undefined symbol: SINCOS") != NULL); ++ ptr = dlsym (handle, "SINCOS"); ++ TEST_VERIFY (ptr == NULL); ++ xdlclose (handle); ++ TEST_COMPARE_STRING (dlerror (), NULL); ++ ++ handle = xdlopen (LIBC_SO, RTLD_LOCAL | RTLD_NOW | RTLD_NOLOAD); ++ ++ /* Check dlvsym. _exit is unlikely to gain another symbol ++ version. */ ++ TEST_VERIFY (xdlsym (handle, "_exit") ++ == xdlvsym (handle, "_exit", FIRST_VERSION_libc__exit_STRING)); ++ ++ /* Check dlinfo. */ ++ { ++ void *handle2 = NULL; ++ TEST_COMPARE (dlinfo (handle, RTLD_DI_LINKMAP, &handle2), 0); ++ TEST_VERIFY (handle2 == handle); ++ } ++ ++ /* Check dladdr and dladdr1. */ ++ Dl_info info = { }; ++ TEST_VERIFY (dladdr (&_exit, &info) != 0); ++ if (strcmp (info.dli_sname, "_Exit") != 0) /* _Exit is an alias. */ ++ TEST_COMPARE_STRING (info.dli_sname, "_exit"); ++ TEST_VERIFY (info.dli_saddr == &_exit); ++ TEST_VERIFY (strstr (info.dli_fname, LIBC_SO)); ++ void *extra_info; ++ memset (&info, 0, sizeof (info)); ++ TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0); ++ TEST_VERIFY (extra_info == handle); ++ ++ /* Verify that dlmopen creates a new namespace. */ ++ void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); ++ TEST_VERIFY (dlmopen_handle != handle); ++ memset (&info, 0, sizeof (info)); ++ extra_info = NULL; ++ ptr = xdlsym (dlmopen_handle, "_exit"); ++ TEST_VERIFY (dladdr1 (ptr, &info, &extra_info, RTLD_DL_LINKMAP) != 0); ++ TEST_VERIFY (extra_info == dlmopen_handle); ++ xdlclose (dlmopen_handle); ++ ++ /* Terminate the process with an error state. This does not happen ++ automatically because the audit module state is not shared with ++ the main program. */ ++ if (support_record_failure_is_failed ()) ++ { ++ fflush (stdout); ++ fflush (stderr); ++ _exit (1); ++ } ++ ++ return LAV_CURRENT; ++} ++ ++char * ++la_objsearch (const char *name, uintptr_t *cookie, unsigned int flag) ++{ ++ if (strcmp (name, "mapped to libc") == 0) ++ return (char *) LIBC_SO; ++ else ++ return (char *) name; ++} diff --git a/SOURCES/glibc-rh2047981-47.patch b/SOURCES/glibc-rh2047981-47.patch new file mode 100644 index 0000000..c5baf0d --- /dev/null +++ b/SOURCES/glibc-rh2047981-47.patch @@ -0,0 +1,59 @@ +commit 2a5b4f7a715921a232f67f6810268c6cd6aa0af2 +Author: Florian Weimer +Date: Fri Jul 8 12:08:48 2022 +0200 + + elf: Rename tst-audit26 to tst-audit28 + + tst-audit26 and tst-audit27 are already used by aarch64. + + Reviewed-by: Szabolcs Nagy + +Conflicts: + elf/Makefile + (Usual test backport differences.) + +diff --git a/elf/Makefile b/elf/Makefile +index 3fae27d32676caf9..9e721d5d4e0a1cd9 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -353,7 +353,7 @@ tests += \ + tst-audit24d \ + tst-audit25a \ + tst-audit25b \ +- tst-audit26 \ ++ tst-audit28 \ + tst-auditmany \ + tst-auxobj \ + tst-auxobj-dlopen \ +@@ -658,7 +658,7 @@ modules-names = \ + tst-auditmod24c \ + tst-auditmod24d \ + tst-auditmod25 \ +- tst-auditmod26 \ ++ tst-auditmod28 \ + tst-big-note-lib \ + tst-deep1mod1 \ + tst-deep1mod2 \ +@@ -2145,10 +2145,10 @@ $(objpfx)tst-audit25b: $(objpfx)tst-audit25mod1.so \ + LDFLAGS-tst-audit25b = -Wl,-z,now + tst-audit25b-ARGS = -- $(host-test-program-cmd) + +-$(objpfx)tst-audit26: $(libdl) +-$(objpfx)tst-audit26.out: $(objpfx)tst-auditmod26.so +-$(objpfx)tst-auditmod26.so: $(libsupport) $(libdl) +-tst-audit26-ENV = LD_AUDIT=$(objpfx)tst-auditmod26.so ++$(objpfx)tst-audit28: $(libdl) ++$(objpfx)tst-audit28.out: $(objpfx)tst-auditmod28.so ++$(objpfx)tst-auditmod28.so: $(libsupport) $(libdl) ++tst-audit28-ENV = LD_AUDIT=$(objpfx)tst-auditmod28.so + + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ +diff --git a/elf/tst-audit26.c b/elf/tst-audit28.c +similarity index 100% +rename from elf/tst-audit26.c +rename to elf/tst-audit28.c +diff --git a/elf/tst-auditmod26.c b/elf/tst-auditmod28.c +similarity index 100% +rename from elf/tst-auditmod26.c +rename to elf/tst-auditmod28.c diff --git a/SOURCES/glibc-rh2047981-5.patch b/SOURCES/glibc-rh2047981-5.patch new file mode 100644 index 0000000..43af14e --- /dev/null +++ b/SOURCES/glibc-rh2047981-5.patch @@ -0,0 +1,224 @@ +commit b2964eb1d9a6b8ab1250e8a881cf406182da5875 +Author: Florian Weimer +Date: Wed Apr 21 19:49:51 2021 +0200 + + dlfcn: Failures after dlmopen should not terminate process [BZ #24772] + + Commit 9e78f6f6e7134a5f299cc8de77370218f8019237 ("Implement + _dl_catch_error, _dl_signal_error in libc.so [BZ #16628]") has the + side effect that distinct namespaces, as created by dlmopen, now have + separate implementations of the rtld exception mechanism. This means + that the call to _dl_catch_error from libdl in a secondary namespace + does not actually install an exception handler because the + thread-local variable catch_hook in the libc.so copy in the secondary + namespace is distinct from that of the base namepace. As a result, a + dlsym/dlopen/... failure in a secondary namespace terminates the process + with a dynamic linker error because it looks to the exception handler + mechanism as if no handler has been installed. + + This commit restores GLRO (dl_catch_error) and uses it to set the + handler in the base namespace. + + Reviewed-by: Adhemerval Zanella + +Conflicts: + elf/Makefile + +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index 06732460ea1512cd..e08ac3afef302817 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -167,8 +167,10 @@ _dlerror_run (void (*operate) (void *), void *args) + result->errstring = NULL; + } + +- result->errcode = _dl_catch_error (&result->objname, &result->errstring, +- &result->malloced, operate, args); ++ result->errcode = GLRO (dl_catch_error) (&result->objname, ++ &result->errstring, ++ &result->malloced, ++ operate, args); + + /* If no error we mark that no error string is available. */ + result->returned = result->errstring == NULL; +diff --git a/elf/Makefile b/elf/Makefile +index a811919ba4568d64..e0919486a14cab1a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -216,6 +216,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ + tst-tls20 tst-tls21 \ + tst-rtld-run-static \ ++ tst-dlmopen-dlerror \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -349,6 +350,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ + libmarkermod5-1 libmarkermod5-2 libmarkermod5-3 libmarkermod5-4 \ + libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \ ++ tst-dlmopen-dlerror-mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1546,6 +1548,10 @@ $(objpfx)tst-sonamemove-dlopen.out: \ + $(objpfx)tst-sonamemove-runmod1.so \ + $(objpfx)tst-sonamemove-runmod2.so + ++$(objpfx)tst-dlmopen-dlerror: $(libdl) ++$(objpfx)tst-dlmopen-dlerror-mod.so: $(libdl) $(libsupport) ++$(objpfx)tst-dlmopen-dlerror.out: $(objpfx)tst-dlmopen-dlerror-mod.so ++ + # Override -z defs, so that we can reference an undefined symbol. + # Force lazy binding for the same reason. + LDFLAGS-tst-latepthreadmod.so = \ +diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c +index 9cb002ccfed2c7b4..7801aa433b12275f 100644 +--- a/elf/dl-error-skeleton.c ++++ b/elf/dl-error-skeleton.c +@@ -248,4 +248,16 @@ _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) + catch_hook = old_catch; + receiver = old_receiver; + } ++ ++/* Forwarder used for initializing GLRO (_dl_catch_error). */ ++int ++_rtld_catch_error (const char **objname, const char **errstring, ++ bool *mallocedp, void (*operate) (void *), ++ void *args) ++{ ++ /* The reference to _dl_catch_error will eventually be relocated to ++ point to the implementation in libc.so. */ ++ return _dl_catch_error (objname, errstring, mallocedp, operate, args); ++} ++ + #endif /* DL_ERROR_BOOTSTRAP */ +diff --git a/elf/rtld.c b/elf/rtld.c +index 461d8c114a875a9b..c445b5ca25dea193 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -365,6 +365,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro = + ._dl_lookup_symbol_x = _dl_lookup_symbol_x, + ._dl_open = _dl_open, + ._dl_close = _dl_close, ++ ._dl_catch_error = _rtld_catch_error, + ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft, + #ifdef HAVE_DL_DISCOVER_OSVERSION + ._dl_discover_osversion = _dl_discover_osversion +diff --git a/elf/tst-dlmopen-dlerror-mod.c b/elf/tst-dlmopen-dlerror-mod.c +new file mode 100644 +index 0000000000000000..7e95dcdeacf005be +--- /dev/null ++++ b/elf/tst-dlmopen-dlerror-mod.c +@@ -0,0 +1,41 @@ ++/* Check that dlfcn errors are reported properly after dlmopen. Test module. ++ 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 ++ ++/* Note: This object is not linked into the main program, so we cannot ++ use delayed test failure reporting via TEST_VERIFY etc., and have ++ to use FAIL_EXIT1 (or something else that calls exit). */ ++ ++void ++call_dlsym (void) ++{ ++ void *ptr = dlsym (NULL, "does not exist"); ++ if (ptr != NULL) ++ FAIL_EXIT1 ("dlsym did not fail as expected"); ++} ++ ++void ++call_dlopen (void) ++{ ++ void *handle = dlopen ("tst-dlmopen-dlerror does not exist", RTLD_NOW); ++ if (handle != NULL) ++ FAIL_EXIT1 ("dlopen did not fail as expected"); ++} +diff --git a/elf/tst-dlmopen-dlerror.c b/elf/tst-dlmopen-dlerror.c +new file mode 100644 +index 0000000000000000..e864d2fe4c3484ab +--- /dev/null ++++ b/elf/tst-dlmopen-dlerror.c +@@ -0,0 +1,37 @@ ++/* Check that dlfcn errors are reported properly after dlmopen. ++ 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 ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-dlerror-mod.so", ++ RTLD_NOW); ++ void (*call_dlsym) (void) = xdlsym (handle, "call_dlsym"); ++ void (*call_dlopen) (void) = xdlsym (handle, "call_dlopen"); ++ ++ call_dlsym (); ++ call_dlopen (); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 7b0a667629ddc06a..d6d02aa3ccffba33 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -647,6 +647,12 @@ struct rtld_global_ro + void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen, + Lmid_t nsid, int argc, char *argv[], char *env[]); + void (*_dl_close) (void *map); ++ /* libdl in a secondary namespace (after dlopen) must use ++ _dl_catch_error from the main namespace, so it has to be ++ exported in some way. */ ++ int (*_dl_catch_error) (const char **objname, const char **errstring, ++ bool *mallocedp, void (*operate) (void *), ++ void *args); + void *(*_dl_tls_get_addr_soft) (struct link_map *); + #ifdef HAVE_DL_DISCOVER_OSVERSION + int (*_dl_discover_osversion) (void); +@@ -889,6 +895,9 @@ extern int _dl_catch_error (const char **objname, const char **errstring, + void *args); + libc_hidden_proto (_dl_catch_error) + ++/* Used for initializing GLRO (_dl_catch_error). */ ++extern __typeof__ (_dl_catch_error) _rtld_catch_error attribute_hidden; ++ + /* Call OPERATE (ARGS). If no error occurs, set *EXCEPTION to zero. + Otherwise, store a copy of the raised exception in *EXCEPTION, + which has to be freed by _dl_exception_free. As a special case, if diff --git a/SOURCES/glibc-rh2047981-6.patch b/SOURCES/glibc-rh2047981-6.patch new file mode 100644 index 0000000..09a5bf8 --- /dev/null +++ b/SOURCES/glibc-rh2047981-6.patch @@ -0,0 +1,822 @@ +commit fada9018199c21c469ff0e731ef75c6020074ac9 +Author: Florian Weimer +Date: Wed Apr 21 19:49:51 2021 +0200 + + dlfcn: dlerror needs to call free from the base namespace [BZ #24773] + + Calling free directly may end up freeing a pointer allocated by the + dynamic loader using malloc from libc.so in the base namespace using + the allocator from libc.so in a secondary namespace, which results in + crashes. + + This commit redirects the free call through GLRO and the dynamic + linker, to reach the correct namespace. It also cleans up the dlerror + handling along the way, so that pthread_setspecific is no longer + needed (which avoids triggering bug 24774). + +Conflicts: + dlfcn/dlfreeres.c - Remove. + malloc/set-freeres.c + Manual merge against disinct set of resources. + malloc/thread-freeres.c + Manual merge against disinct set of resources. + +diff --git a/dlfcn/Makefile b/dlfcn/Makefile +index 34f9923334f42edf..0b213b7d9fefcdc9 100644 +--- a/dlfcn/Makefile ++++ b/dlfcn/Makefile +@@ -22,9 +22,10 @@ include ../Makeconfig + headers := bits/dlfcn.h dlfcn.h + extra-libs := libdl + libdl-routines := dlopen dlclose dlsym dlvsym dlerror dladdr dladdr1 dlinfo \ +- dlmopen dlfcn dlfreeres ++ dlmopen dlfcn + routines := $(patsubst %,s%,$(filter-out dlfcn,$(libdl-routines))) + elide-routines.os := $(routines) ++routines += libc_dlerror_result + + extra-libs-others := libdl + +diff --git a/dlfcn/Versions b/dlfcn/Versions +index 1df6925a92ff8b36..f07cb929aa13eaf2 100644 +--- a/dlfcn/Versions ++++ b/dlfcn/Versions +@@ -1,3 +1,8 @@ ++libc { ++ GLIBC_PRIVATE { ++ __libc_dlerror_result; ++ } ++} + libdl { + GLIBC_2.0 { + dladdr; dlclose; dlerror; dlopen; dlsym; +@@ -13,6 +18,5 @@ libdl { + } + GLIBC_PRIVATE { + _dlfcn_hook; +- __libdl_freeres; + } + } +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index e08ac3afef302817..070eadbf7c1c0b1c 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -25,6 +25,8 @@ + #include + #include + #include ++#include ++#include + + #if !defined SHARED && IS_IN (libdl) + +@@ -36,92 +38,75 @@ dlerror (void) + + #else + +-/* Type for storing results of dynamic loading actions. */ +-struct dl_action_result +- { +- int errcode; +- int returned; +- bool malloced; +- const char *objname; +- const char *errstring; +- }; +-static struct dl_action_result last_result; +-static struct dl_action_result *static_buf; +- +-/* This is the key for the thread specific memory. */ +-static __libc_key_t key; +-__libc_once_define (static, once); +- +-/* Destructor for the thread-specific data. */ +-static void init (void); +-static void free_key_mem (void *mem); +- +- + char * + __dlerror (void) + { +- char *buf = NULL; +- struct dl_action_result *result; +- + # ifdef SHARED + if (!rtld_active ()) + return _dlfcn_hook->dlerror (); + # endif + +- /* If we have not yet initialized the buffer do it now. */ +- __libc_once (once, init); ++ struct dl_action_result *result = __libc_dlerror_result; + +- /* Get error string. */ +- if (static_buf != NULL) +- result = static_buf; +- else ++ /* No libdl function has been called. No error is possible. */ ++ if (result == NULL) ++ return NULL; ++ ++ /* For an early malloc failure, clear the error flag and return the ++ error message. This marks the error as delivered. */ ++ if (result == dl_action_result_malloc_failed) + { +- /* init () has been run and we don't use the static buffer. +- So we have a valid key. */ +- result = (struct dl_action_result *) __libc_getspecific (key); +- if (result == NULL) +- result = &last_result; ++ __libc_dlerror_result = NULL; ++ return (char *) "out of memory"; + } + +- /* Test whether we already returned the string. */ +- if (result->returned != 0) ++ /* Placeholder object. This can be observed in a recursive call, ++ e.g. from an ELF constructor. */ ++ if (result->errstring == NULL) ++ return NULL; ++ ++ /* If we have already reported the error, we can free the result and ++ return NULL. See __libc_dlerror_result_free. */ ++ if (result->returned) + { +- /* We can now free the string. */ +- if (result->errstring != NULL) +- { +- if (strcmp (result->errstring, "out of memory") != 0) +- free ((char *) result->errstring); +- result->errstring = NULL; +- } ++ __libc_dlerror_result = NULL; ++ dl_action_result_errstring_free (result); ++ free (result); ++ return NULL; + } +- else if (result->errstring != NULL) +- { +- buf = (char *) result->errstring; +- int n; +- if (result->errcode == 0) +- n = __asprintf (&buf, "%s%s%s", +- result->objname, +- result->objname[0] == '\0' ? "" : ": ", +- _(result->errstring)); +- else +- n = __asprintf (&buf, "%s%s%s: %s", +- result->objname, +- result->objname[0] == '\0' ? "" : ": ", +- _(result->errstring), +- strerror (result->errcode)); +- if (n != -1) +- { +- /* We don't need the error string anymore. */ +- if (strcmp (result->errstring, "out of memory") != 0) +- free ((char *) result->errstring); +- result->errstring = buf; +- } + +- /* Mark the error as returned. */ +- result->returned = 1; +- } ++ assert (result->errstring != NULL); ++ ++ /* Create the combined error message. */ ++ char *buf; ++ int n; ++ if (result->errcode == 0) ++ n = __asprintf (&buf, "%s%s%s", ++ result->objname, ++ result->objname[0] == '\0' ? "" : ": ", ++ _(result->errstring)); ++ else ++ n = __asprintf (&buf, "%s%s%s: %s", ++ result->objname, ++ result->objname[0] == '\0' ? "" : ": ", ++ _(result->errstring), ++ strerror (result->errcode)); + +- return buf; ++ /* Mark the error as delivered. */ ++ result->returned = true; ++ ++ if (n >= 0) ++ { ++ /* Replace the error string with the newly allocated one. */ ++ dl_action_result_errstring_free (result); ++ result->errstring = buf; ++ result->errstring_source = dl_action_result_errstring_local; ++ return buf; ++ } ++ else ++ /* We could not create the combined error message, so use the ++ existing string as a fallback. */ ++ return result->errstring; + } + # ifdef SHARED + strong_alias (__dlerror, dlerror) +@@ -130,130 +115,94 @@ strong_alias (__dlerror, dlerror) + int + _dlerror_run (void (*operate) (void *), void *args) + { +- struct dl_action_result *result; +- +- /* If we have not yet initialized the buffer do it now. */ +- __libc_once (once, init); +- +- /* Get error string and number. */ +- if (static_buf != NULL) +- result = static_buf; +- else ++ struct dl_action_result *result = __libc_dlerror_result; ++ if (result != NULL) + { +- /* We don't use the static buffer and so we have a key. Use it +- to get the thread-specific buffer. */ +- result = __libc_getspecific (key); +- if (result == NULL) ++ if (result == dl_action_result_malloc_failed) + { +- result = (struct dl_action_result *) calloc (1, sizeof (*result)); +- if (result == NULL) +- /* We are out of memory. Since this is no really critical +- situation we carry on by using the global variable. +- This might lead to conflicts between the threads but +- they soon all will have memory problems. */ +- result = &last_result; +- else +- /* Set the tsd. */ +- __libc_setspecific (key, result); ++ /* Clear the previous error. */ ++ __libc_dlerror_result = NULL; ++ result = NULL; ++ } ++ else ++ { ++ /* There is an existing object. Free its error string, but ++ keep the object. */ ++ dl_action_result_errstring_free (result); ++ /* Mark the object as not containing an error. This ensures ++ that call to dlerror from, for example, an ELF ++ constructor will not notice this result object. */ ++ result->errstring = NULL; + } + } + +- if (result->errstring != NULL) +- { +- /* Free the error string from the last failed command. This can +- happen if `dlerror' was not run after an error was found. */ +- if (result->malloced) +- free ((char *) result->errstring); +- result->errstring = NULL; +- } +- +- result->errcode = GLRO (dl_catch_error) (&result->objname, +- &result->errstring, +- &result->malloced, +- operate, args); +- +- /* If no error we mark that no error string is available. */ +- result->returned = result->errstring == NULL; ++ const char *objname; ++ const char *errstring; ++ bool malloced; ++ int errcode = GLRO (dl_catch_error) (&objname, &errstring, &malloced, ++ operate, args); + +- return result->errstring != NULL; +-} ++ /* ELF constructors or destructors may have indirectly altered the ++ value of __libc_dlerror_result, therefore reload it. */ ++ result = __libc_dlerror_result; + +- +-/* Initialize buffers for results. */ +-static void +-init (void) +-{ +- if (__libc_key_create (&key, free_key_mem)) +- /* Creating the key failed. This means something really went +- wrong. In any case use a static buffer which is better than +- nothing. */ +- static_buf = &last_result; +-} +- +- +-static void +-check_free (struct dl_action_result *rec) +-{ +- if (rec->errstring != NULL +- && strcmp (rec->errstring, "out of memory") != 0) ++ if (errstring == NULL) + { +- /* We can free the string only if the allocation happened in the +- C library used by the dynamic linker. This means, it is +- always the C library in the base namespace. When we're statically +- linked, the dynamic linker is part of the program and so always +- uses the same C library we use here. */ +-#ifdef SHARED +- struct link_map *map = NULL; +- Dl_info info; +- if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0) +-#endif ++ /* There is no error. We no longer need the result object if it ++ does not contain an error. However, a recursive call may ++ have added an error even if this call did not cause it. Keep ++ the other error. */ ++ if (result != NULL && result->errstring == NULL) + { +- free ((char *) rec->errstring); +- rec->errstring = NULL; ++ __libc_dlerror_result = NULL; ++ free (result); + } ++ return 0; + } +-} +- +- +-static void +-__attribute__ ((destructor)) +-fini (void) +-{ +- check_free (&last_result); +-} +- +- +-/* Free the thread specific data, this is done if a thread terminates. */ +-static void +-free_key_mem (void *mem) +-{ +- check_free ((struct dl_action_result *) mem); ++ else ++ { ++ /* A new error occurred. Check if a result object has to be ++ allocated. */ ++ if (result == NULL || result == dl_action_result_malloc_failed) ++ { ++ /* Allocating storage for the error message after the fact ++ is not ideal. But this avoids an infinite recursion in ++ case malloc itself calls libdl functions (without ++ triggering errors). */ ++ result = malloc (sizeof (*result)); ++ if (result == NULL) ++ { ++ /* Assume that the dlfcn failure was due to a malloc ++ failure, too. */ ++ if (malloced) ++ dl_error_free ((char *) errstring); ++ __libc_dlerror_result = dl_action_result_malloc_failed; ++ return 1; ++ } ++ __libc_dlerror_result = result; ++ } ++ else ++ /* Deallocate the existing error message from a recursive ++ call, but reuse the result object. */ ++ dl_action_result_errstring_free (result); ++ ++ result->errcode = errcode; ++ result->objname = objname; ++ result->errstring = (char *) errstring; ++ result->returned = false; ++ /* In case of an error, the malloced flag indicates whether the ++ error string is constant or not. */ ++ if (malloced) ++ result->errstring_source = dl_action_result_errstring_rtld; ++ else ++ result->errstring_source = dl_action_result_errstring_constant; + +- free (mem); +- __libc_setspecific (key, NULL); ++ return 1; ++ } + } + + # ifdef SHARED + +-/* Free the dlerror-related resources. */ +-void +-__dlerror_main_freeres (void) +-{ +- /* Free the global memory if used. */ +- check_free (&last_result); +- +- if (__libc_once_get (once) && static_buf == NULL) +- { +- /* init () has been run and we don't use the static buffer. +- So we have a valid key. */ +- void *mem; +- /* Free the TSD memory if used. */ +- mem = __libc_getspecific (key); +- if (mem != NULL) +- free_key_mem (mem); +- } +-} +- + struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon)); + libdl_hidden_data_def (_dlfcn_hook) + +diff --git a/dlfcn/dlerror.h b/dlfcn/dlerror.h +new file mode 100644 +index 0000000000000000..cb9a9cea4c009452 +--- /dev/null ++++ b/dlfcn/dlerror.h +@@ -0,0 +1,92 @@ ++/* Memory management for dlerror messages. ++ 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 ++ . */ ++ ++#ifndef _DLERROR_H ++#define _DLERROR_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Source of the errstring member in struct dl_action_result, for ++ finding the right deallocation routine. */ ++enum dl_action_result_errstring_source ++ { ++ dl_action_result_errstring_constant, /* String literal, no deallocation. */ ++ dl_action_result_errstring_rtld, /* libc in the primary namespace. */ ++ dl_action_result_errstring_local, /* libc in the current namespace. */ ++ }; ++ ++struct dl_action_result ++{ ++ int errcode; ++ char errstring_source; ++ bool returned; ++ const char *objname; ++ char *errstring; ++}; ++ ++/* Used to free the errstring member of struct dl_action_result in the ++ dl_action_result_errstring_rtld case. */ ++static inline void ++dl_error_free (void *ptr) ++{ ++#ifdef SHARED ++ /* In the shared case, ld.so may use a different malloc than this ++ namespace. */ ++ GLRO (dl_error_free (ptr)); ++#else ++ /* Call the implementation directly. It still has to check for ++ pointers which cannot be freed, so do not call free directly ++ here. */ ++ _dl_error_free (ptr); ++#endif ++} ++ ++/* Deallocate RESULT->errstring, leaving *RESULT itself allocated. */ ++static inline void ++dl_action_result_errstring_free (struct dl_action_result *result) ++{ ++ switch (result->errstring_source) ++ { ++ case dl_action_result_errstring_constant: ++ break; ++ case dl_action_result_errstring_rtld: ++ dl_error_free (result->errstring); ++ break; ++ case dl_action_result_errstring_local: ++ free (result->errstring); ++ break; ++ } ++} ++ ++/* Stand-in for an error result object whose allocation failed. No ++ precise message can be reported for this, but an error must still ++ be signaled. */ ++static struct dl_action_result *const dl_action_result_malloc_failed ++ __attribute__ ((unused)) = (struct dl_action_result *) (intptr_t) -1; ++ ++/* Thread-local variable for storing dlfcn failures for subsequent ++ reporting via dlerror. */ ++extern __thread struct dl_action_result *__libc_dlerror_result ++ attribute_tls_model_ie; ++void __libc_dlerror_result_free (void) attribute_hidden; ++ ++#endif /* _DLERROR_H */ +diff --git a/dlfcn/dlfreeres.c b/dlfcn/dlfreeres.c +deleted file mode 100644 +index 4004db0edbe0c028..0000000000000000 +--- a/dlfcn/dlfreeres.c ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* Clean up allocated libdl memory on demand. +- Copyright (C) 2018 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 +- +-/* Free libdl.so resources. +- Note: Caller ensures we are called only once. */ +-void +-__libdl_freeres (void) +-{ +- call_function_static_weak (__dlerror_main_freeres); +-} +diff --git a/dlfcn/libc_dlerror_result.c b/dlfcn/libc_dlerror_result.c +new file mode 100644 +index 0000000000000000..99747186b9218680 +--- /dev/null ++++ b/dlfcn/libc_dlerror_result.c +@@ -0,0 +1,39 @@ ++/* Thread-local variable holding the dlerror result. ++ 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 ++ ++/* This pointer is either NULL, dl_action_result_malloc_failed (), or ++ has been allocated using malloc by the namespace that also contains ++ this instance of the thread-local variable. */ ++__thread struct dl_action_result *__libc_dlerror_result attribute_tls_model_ie; ++ ++/* Called during thread shutdown to free resources. */ ++void ++__libc_dlerror_result_free (void) ++{ ++ if (__libc_dlerror_result != NULL) ++ { ++ if (__libc_dlerror_result != dl_action_result_malloc_failed) ++ { ++ dl_action_result_errstring_free (__libc_dlerror_result); ++ free (__libc_dlerror_result); ++ } ++ __libc_dlerror_result = NULL; ++ } ++} +diff --git a/elf/dl-exception.c b/elf/dl-exception.c +index d24bf30a5cf39bc2..f474daf97ae76308 100644 +--- a/elf/dl-exception.c ++++ b/elf/dl-exception.c +@@ -30,6 +30,17 @@ + a pointer comparison. See below and in dlfcn/dlerror.c. */ + static const char _dl_out_of_memory[] = "out of memory"; + ++/* Call free in the main libc.so. This allows other namespaces to ++ free pointers on the main libc heap, via GLRO (dl_error_free). It ++ also avoids calling free on the special, pre-allocated ++ out-of-memory error message. */ ++void ++_dl_error_free (void *ptr) ++{ ++ if (ptr != _dl_out_of_memory) ++ free (ptr); ++} ++ + /* Dummy allocation object used if allocating the message buffer + fails. */ + static void +diff --git a/elf/rtld.c b/elf/rtld.c +index c445b5ca25dea193..e107af4014d43777 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -366,6 +366,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro = + ._dl_open = _dl_open, + ._dl_close = _dl_close, + ._dl_catch_error = _rtld_catch_error, ++ ._dl_error_free = _dl_error_free, + ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft, + #ifdef HAVE_DL_DISCOVER_OSVERSION + ._dl_discover_osversion = _dl_discover_osversion +diff --git a/elf/tst-dlmopen-dlerror-mod.c b/elf/tst-dlmopen-dlerror-mod.c +index 7e95dcdeacf005be..051025d3fa7a4d6a 100644 +--- a/elf/tst-dlmopen-dlerror-mod.c ++++ b/elf/tst-dlmopen-dlerror-mod.c +@@ -18,6 +18,8 @@ + + #include + #include ++#include ++#include + #include + + /* Note: This object is not linked into the main program, so we cannot +@@ -25,17 +27,32 @@ + to use FAIL_EXIT1 (or something else that calls exit). */ + + void +-call_dlsym (void) ++call_dlsym (const char *name) + { +- void *ptr = dlsym (NULL, "does not exist"); ++ void *ptr = dlsym (NULL, name); + if (ptr != NULL) +- FAIL_EXIT1 ("dlsym did not fail as expected"); ++ FAIL_EXIT1 ("dlsym did not fail as expected for: %s", name); ++ const char *message = dlerror (); ++ if (strstr (message, ": undefined symbol: does not exist X") == NULL) ++ FAIL_EXIT1 ("invalid dlsym error message for [[%s]]: %s", name, message); ++ message = dlerror (); ++ if (message != NULL) ++ FAIL_EXIT1 ("second dlsym for [[%s]]: %s", name, message); + } + + void +-call_dlopen (void) ++call_dlopen (const char *name) + { +- void *handle = dlopen ("tst-dlmopen-dlerror does not exist", RTLD_NOW); ++ void *handle = dlopen (name, RTLD_NOW); + if (handle != NULL) +- FAIL_EXIT1 ("dlopen did not fail as expected"); ++ FAIL_EXIT1 ("dlopen did not fail as expected for: %s", name); ++ const char *message = dlerror (); ++ if (strstr (message, "X: cannot open shared object file:" ++ " No such file or directory") == NULL ++ && strstr (message, "X: cannot open shared object file:" ++ " File name too long") == NULL) ++ FAIL_EXIT1 ("invalid dlopen error message for [[%s]]: %s", name, message); ++ message = dlerror (); ++ if (message != NULL) ++ FAIL_EXIT1 ("second dlopen for [[%s]]: %s", name, message); + } +diff --git a/elf/tst-dlmopen-dlerror.c b/elf/tst-dlmopen-dlerror.c +index e864d2fe4c3484ab..aa3d6598df119ce0 100644 +--- a/elf/tst-dlmopen-dlerror.c ++++ b/elf/tst-dlmopen-dlerror.c +@@ -17,6 +17,7 @@ + . */ + + #include ++#include + #include + #include + +@@ -25,11 +26,22 @@ do_test (void) + { + void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-dlerror-mod.so", + RTLD_NOW); +- void (*call_dlsym) (void) = xdlsym (handle, "call_dlsym"); +- void (*call_dlopen) (void) = xdlsym (handle, "call_dlopen"); +- +- call_dlsym (); +- call_dlopen (); ++ void (*call_dlsym) (const char *name) = xdlsym (handle, "call_dlsym"); ++ void (*call_dlopen) (const char *name) = xdlsym (handle, "call_dlopen"); ++ ++ /* Iterate over various name lengths. This changes the size of ++ error messages allocated by ld.so and has been shown to trigger ++ detectable heap corruption if malloc/free calls in different ++ namespaces are mixed. */ ++ char buffer[2048]; ++ char *buffer_end = &buffer[sizeof (buffer) - 2]; ++ for (char *p = stpcpy (buffer, "does not exist "); p < buffer_end; ++p) ++ { ++ p[0] = 'X'; ++ p[1] = '\0'; ++ call_dlsym (buffer); ++ call_dlopen (buffer); ++ } + + return 0; + } +diff --git a/include/dlfcn.h b/include/dlfcn.h +index 0dc57dbe2217cfe7..109586a1d968b630 100644 +--- a/include/dlfcn.h ++++ b/include/dlfcn.h +@@ -156,7 +156,5 @@ extern void __libc_register_dlfcn_hook (struct link_map *map) + attribute_hidden; + #endif + +-extern void __dlerror_main_freeres (void) attribute_hidden; +- + #endif + #endif +diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c +index cda368479f910149..43b6a2cd9da49aa9 100644 +--- a/malloc/set-freeres.c ++++ b/malloc/set-freeres.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include "../libio/libioP.h" + +@@ -26,8 +27,6 @@ DEFINE_HOOK (__libc_subfreeres, (void)); + + symbol_set_define (__libc_freeres_ptrs); + +-extern __attribute__ ((weak)) void __libdl_freeres (void); +- + extern __attribute__ ((weak)) void __libpthread_freeres (void); + + void __libc_freeres_fn_section +@@ -46,16 +45,13 @@ __libc_freeres (void) + /* We run the resource freeing after IO cleanup. */ + RUN_HOOK (__libc_subfreeres, ()); + +- /* Call the libdl list of cleanup functions +- (weak-ref-and-check). */ +- if (&__libdl_freeres != NULL) +- __libdl_freeres (); +- + /* Call the libpthread list of cleanup functions + (weak-ref-and-check). */ + if (&__libpthread_freeres != NULL) + __libpthread_freeres (); + ++ call_function_static_weak (__libc_dlerror_result_free); ++ + for (p = symbol_set_first_element (__libc_freeres_ptrs); + !symbol_set_end_p (__libc_freeres_ptrs, p); ++p) + free (*p); +diff --git a/malloc/thread-freeres.c b/malloc/thread-freeres.c +index a63b6c93f3114284..1e37a72c1f4a9c43 100644 +--- a/malloc/thread-freeres.c ++++ b/malloc/thread-freeres.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include +@@ -32,6 +33,7 @@ __libc_thread_freeres (void) + call_function_static_weak (__rpc_thread_destroy); + call_function_static_weak (__res_thread_freeres); + call_function_static_weak (__strerror_thread_freeres); ++ call_function_static_weak (__libc_dlerror_result_free); + + /* This should come last because it shuts down malloc for this + thread and the other shutdown functions might well call free. */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index d6d02aa3ccffba33..2dd6f0c3c4aaaef5 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -653,6 +653,9 @@ struct rtld_global_ro + int (*_dl_catch_error) (const char **objname, const char **errstring, + bool *mallocedp, void (*operate) (void *), + void *args); ++ /* libdl in a secondary namespace must use free from the base ++ namespace. */ ++ void (*_dl_error_free) (void *); + void *(*_dl_tls_get_addr_soft) (struct link_map *); + #ifdef HAVE_DL_DISCOVER_OSVERSION + int (*_dl_discover_osversion) (void); +@@ -812,6 +815,10 @@ void _dl_exception_create (struct dl_exception *, const char *object, + __attribute__ ((nonnull (1, 3))); + rtld_hidden_proto (_dl_exception_create) + ++/* Used internally to implement dlerror message freeing. See ++ include/dlfcn.h and dlfcn/dlerror.c. */ ++void _dl_error_free (void *ptr) attribute_hidden; ++ + /* Like _dl_exception_create, but create errstring from a format + string FMT. Currently, only "%s" and "%%" are supported as format + directives. */ diff --git a/SOURCES/glibc-rh2047981-7.patch b/SOURCES/glibc-rh2047981-7.patch new file mode 100644 index 0000000..d1640be --- /dev/null +++ b/SOURCES/glibc-rh2047981-7.patch @@ -0,0 +1,134 @@ +Added $(objpfx)tst-dlmopen-gethostbyname: $(libdl) in elf/Makefile since +we still have $(libdl) in RHEL8. + +commit c2059edce20c124d1a99f1a94cc52e83b77a917a +Author: Florian Weimer +Date: Thu Jun 17 15:06:43 2021 +0200 + + elf: Use _dl_catch_error from base namespace in dl-libc.c [BZ #27646] + + dlerrror_run in elf/dl-libc.c needs to call GLRO (dl_catch_error) + from the base namespace, just like the exported dlerror + implementation. + + Fixes commit b2964eb1d9a6b8ab1250e8a881cf406182da5875 ("dlfcn: + Failures after dlmopen should not terminate process [BZ #24772]"). + + Reviewed-by: Siddhesh Poyarekar + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index e0919486a14cab1a..30417c3ce15abcb4 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -217,6 +217,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tls20 tst-tls21 \ + tst-rtld-run-static \ + tst-dlmopen-dlerror \ ++ tst-dlmopen-gethostbyname \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -351,6 +352,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + libmarkermod5-1 libmarkermod5-2 libmarkermod5-3 libmarkermod5-4 \ + libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \ + tst-dlmopen-dlerror-mod \ ++ tst-dlmopen-gethostbyname-mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1935,3 +1937,5 @@ $(objpfx)tst-tls21.out: $(objpfx)tst-tls21mod.so + $(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so) + + $(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig ++$(objpfx)tst-dlmopen-gethostbyname: $(libdl) ++$(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so +diff --git a/elf/dl-libc.c b/elf/dl-libc.c +index fc01f5514d4f656c..3a242d219756dac6 100644 +--- a/elf/dl-libc.c ++++ b/elf/dl-libc.c +@@ -43,8 +43,8 @@ dlerror_run (void (*operate) (void *), void *args) + const char *last_errstring = NULL; + bool malloced; + +- int result = (_dl_catch_error (&objname, &last_errstring, &malloced, +- operate, args) ++ int result = (GLRO (dl_catch_error) (&objname, &last_errstring, &malloced, ++ operate, args) + ?: last_errstring != NULL); + + if (result && malloced) +diff --git a/elf/tst-dlmopen-gethostbyname-mod.c b/elf/tst-dlmopen-gethostbyname-mod.c +new file mode 100644 +index 0000000000000000..9a68ea5050c3060b +--- /dev/null ++++ b/elf/tst-dlmopen-gethostbyname-mod.c +@@ -0,0 +1,29 @@ ++/* Exercise dlerror_run in elf/dl-libc.c after dlmopen, via NSS. Helper module. ++ 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 ++ ++void ++call_gethostbyname (void) ++{ ++ __nss_configure_lookup ("hosts", "files"); ++ /* This should not terminate the process due to a missing ++ _nss_files_getcanonname_r symbol. */ ++ gethostbyname ("localhost"); ++} +diff --git a/elf/tst-dlmopen-gethostbyname.c b/elf/tst-dlmopen-gethostbyname.c +new file mode 100644 +index 0000000000000000..12deb29900731c20 +--- /dev/null ++++ b/elf/tst-dlmopen-gethostbyname.c +@@ -0,0 +1,31 @@ ++/* Exercise dlerror_run in elf/dl-libc.c after dlmopen, via NSS (bug 27646). ++ 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 ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-gethostbyname-mod.so", ++ RTLD_NOW); ++ void (*call_gethostbyname) (void) = xdlsym (handle, "call_gethostbyname"); ++ call_gethostbyname (); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh2047981-8.patch b/SOURCES/glibc-rh2047981-8.patch new file mode 100644 index 0000000..885aad4 --- /dev/null +++ b/SOURCES/glibc-rh2047981-8.patch @@ -0,0 +1,29 @@ +commit 832f50be6c9c010e46180d14126bbb81f35e808c +Author: Florian Weimer +Date: Tue Jul 6 13:22:01 2021 +0200 + + elf: Call free from base namespace on error in dl-libc.c [BZ #27646] + + In dlerror_run, free corresponds to the local malloc in the + namespace, but GLRO (dl_catch_error) uses the malloc from the base + namespace. elf/tst-dlmopen-gethostbyname triggers this mismatch, + but it does not crash, presumably because of a fastbin deallocation. + + Fixes commit c2059edce20c124d1a99f1a94cc52e83b77a917a ("elf: Use + _dl_catch_error from base namespace in dl-libc.c [BZ #27646]") and + commit b2964eb1d9a6b8ab1250e8a881cf406182da5875 ("dlfcn: Failures + after dlmopen should not terminate process [BZ #24772]"). + +diff --git a/elf/dl-libc.c b/elf/dl-libc.c +index 3a242d219756dac6..bb6e3378d546b234 100644 +--- a/elf/dl-libc.c ++++ b/elf/dl-libc.c +@@ -48,7 +48,7 @@ dlerror_run (void (*operate) (void *), void *args) + ?: last_errstring != NULL); + + if (result && malloced) +- free ((char *) last_errstring); ++ GLRO (dl_error_free) ((char *) last_errstring); + + return result; + } diff --git a/SOURCES/glibc-rh2047981-9.patch b/SOURCES/glibc-rh2047981-9.patch new file mode 100644 index 0000000..690027f --- /dev/null +++ b/SOURCES/glibc-rh2047981-9.patch @@ -0,0 +1,126 @@ +commit 3908fa933a4354309225af616d9242f595e11ccf +Author: Adhemerval Zanella +Date: Wed Jun 30 00:21:18 2021 -0300 + + elf: Fix audit regression + + Commit 03e187a41d9 added a regression when an audit module does not have + libc as DT_NEEDED (although unusual it is possible). + + Checked on x86_64-linux-gnu. + +Conflicts: + elf/Makefile + +diff --git a/elf/Makefile b/elf/Makefile +index 30417c3ce15abcb4..6262a4a65cfd2148 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -218,6 +218,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-rtld-run-static \ + tst-dlmopen-dlerror \ + tst-dlmopen-gethostbyname \ ++ tst-audit17 \ + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -1527,6 +1528,16 @@ $(objpfx)tst-auditlogmod-3.so: $(libsupport) + $(objpfx)tst-audit16.out: \ + $(objpfx)tst-auditlogmod-1.so $(objpfx)tst-auditlogmod-2.so \ + $(objpfx)tst-auditlogmod-3.so ++$(objpfx)tst-audit17.out: $(objpfx)tst-auditmod17.so ++# The test check if a audit library without libc.so on DT_NEEDED works as ++# intended, so it uses an explicit link rule. ++$(objpfx)tst-auditmod17.so: $(objpfx)tst-auditmod17.os ++ $(CC) -nostdlib -nostartfiles -shared -o $@.new \ ++ $(filter-out $(map-file),$^) ++ $(call after-link,$@.new) ++ mv -f $@.new $@ ++CFLAGS-.os += $(call elide-stack-protector,.os,tst-auditmod17) ++tst-audit17-ENV = LD_AUDIT=$(objpfx)tst-auditmod17.so + + # tst-sonamemove links against an older implementation of the library. + LDFLAGS-tst-sonamemove-linkmod1.so = \ +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 736df62ce6e46d34..661a2172d1789b26 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -759,16 +759,9 @@ dl_open_worker_begin (void *a) + namespace. */ + if (!args->libc_already_loaded) + { ++ /* dlopen cannot be used to load an initial libc by design. */ + struct link_map *libc_map = GL(dl_ns)[args->nsid].libc_map; +-#ifdef SHARED +- bool initial = libc_map->l_ns == LM_ID_BASE; +-#else +- /* In the static case, there is only one namespace, but it +- contains a secondary libc (the primary libc is statically +- linked). */ +- bool initial = false; +-#endif +- _dl_call_libc_early_init (libc_map, initial); ++ _dl_call_libc_early_init (libc_map, false); + } + + #ifndef SHARED +diff --git a/elf/tst-audit17.c b/elf/tst-audit17.c +new file mode 100644 +index 0000000000000000..92986699d497845f +--- /dev/null ++++ b/elf/tst-audit17.c +@@ -0,0 +1,25 @@ ++/* Check DT_AUDIT with audit not linked against libc. ++ 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 ++ . */ ++ ++static int ++do_test (void) ++{ ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-auditmod17.c b/elf/tst-auditmod17.c +new file mode 100644 +index 0000000000000000..7a4467f597b56cf4 +--- /dev/null ++++ b/elf/tst-auditmod17.c +@@ -0,0 +1,23 @@ ++/* Check DT_AUDIT with audit not linked against libc. ++ 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 ++ . */ ++ ++unsigned int ++la_version (unsigned int version) ++{ ++ return version; ++} diff --git a/SOURCES/glibc-rh2054790.patch b/SOURCES/glibc-rh2054790.patch new file mode 100644 index 0000000..6af769e --- /dev/null +++ b/SOURCES/glibc-rh2054790.patch @@ -0,0 +1,27 @@ +commit ea89d5bbd9e5e514b606045d909e6ab87d851c88 +Author: Arjun Shankar +Date: Thu Feb 24 21:43:09 2022 +0100 + + localedef: Handle symbolic links when generating locale-archive + + Whenever locale data for any locale included symbolic links, localedef + would throw the error "incomplete set of locale files" and exclude it + from the generated locale archive. This commit fixes that. + + Co-authored-by: Florian Weimer + + Reviewed-by: Carlos O'Donell + +diff --git a/locale/programs/locarchive.c b/locale/programs/locarchive.c +index dec73264563bc2a0..990f7eb6830d2e57 100644 +--- a/locale/programs/locarchive.c ++++ b/locale/programs/locarchive.c +@@ -1391,7 +1391,7 @@ add_locales_to_archive (size_t nlist, char *list[], bool replace) + { + char fullname[fnamelen + 2 * strlen (d->d_name) + 7]; + +- if (d_type == DT_UNKNOWN) ++ if (d_type == DT_UNKNOWN || d_type == DT_LNK) + { + strcpy (stpcpy (stpcpy (fullname, fname), "/"), + d->d_name); diff --git a/SOURCES/glibc-rh2063042.patch b/SOURCES/glibc-rh2063042.patch new file mode 100644 index 0000000..921add1 --- /dev/null +++ b/SOURCES/glibc-rh2063042.patch @@ -0,0 +1,358 @@ +commit fcfc9086815bf0d277ad47a90ee3fda4c37acca8 +Author: Siddhesh Poyarekar +Date: Wed Jan 12 23:34:48 2022 +0530 + + debug: Synchronize feature guards in fortified functions [BZ #28746] + + Some functions (e.g. stpcpy, pread64, etc.) had moved to POSIX in the + main headers as they got incorporated into the standard, but their + fortified variants remained under __USE_GNU. As a result, these + functions did not get fortified when _GNU_SOURCE was not defined. + + Add test wrappers that check all functions tested in tst-chk0 at all + levels with _GNU_SOURCE undefined and then use the failures to (1) + exclude checks for _GNU_SOURCE functions in these tests and (2) Fix + feature macro guards in the fortified function headers so that they're + the same as the ones in the main headers. + + This fixes BZ #28746. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Adhemerval Zanella + +# Conflicts: +# debug/tst-fortify.c + +diff --git a/debug/Makefile b/debug/Makefile +index c92fd23dda1a7279..b0f0b7beb6d5cef5 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -132,6 +132,12 @@ define cflags-lfs + CFLAGS-tst-fortify-$(1)-lfs-$(2).$(1) += -D_FILE_OFFSET_BITS=64 + endef + ++define cflags-nongnu ++CFLAGS-tst-fortify-$(1)-nongnu-$(2).$(1) += -D_LARGEFILE64_SOURCE=1 ++endef ++ ++src-chk-nongnu = \#undef _GNU_SOURCE ++ + # We know these tests have problems with format strings, this is what + # we are testing. Disable that warning. They are also testing + # deprecated functions (notably gets) so disable that warning as well. +@@ -145,13 +151,13 @@ CFLAGS-tst-fortify-$(1)-$(2)-$(3).$(1) += -D_FORTIFY_SOURCE=$(3) -Wno-format \ + $(eval $(call cflags-$(2),$(1),$(3))) + $(objpfx)tst-fortify-$(1)-$(2)-$(3).$(1): tst-fortify.c Makefile + ( echo "/* Autogenerated from Makefile. */"; \ +- echo ""; \ ++ echo "$(src-chk-$(2))"; \ + echo "#include \"tst-fortify.c\"" ) > $$@.tmp + mv $$@.tmp $$@ + endef + + chk-extensions = c cc +-chk-types = default lfs ++chk-types = default lfs nongnu + chk-levels = 1 2 3 + + $(foreach e,$(chk-extensions), \ +diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c +index 5e76081255316a93..1668294e48b5c63c 100644 +--- a/debug/tst-fortify.c ++++ b/debug/tst-fortify.c +@@ -1,4 +1,5 @@ +-/* Copyright (C) 2004-2018 Free Software Foundation, Inc. ++/* Copyright (C) 2004-2022 Free Software Foundation, Inc. ++ Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2004. + +@@ -37,6 +38,17 @@ + #include + #include + ++#ifndef _GNU_SOURCE ++# define MEMPCPY memcpy ++# define WMEMPCPY wmemcpy ++# define MEMPCPY_RET(x) 0 ++# define WMEMPCPY_RET(x) 0 ++#else ++# define MEMPCPY mempcpy ++# define WMEMPCPY wmempcpy ++# define MEMPCPY_RET(x) __builtin_strlen (x) ++# define WMEMPCPY_RET(x) wcslen (x) ++#endif + + #define obstack_chunk_alloc malloc + #define obstack_chunk_free free +@@ -163,7 +175,7 @@ do_test (void) + if (memcmp (buf, "aabcdefghi", 10)) + FAIL (); + +- if (mempcpy (buf + 5, "abcde", 5) != buf + 10 ++ if (MEMPCPY (buf + 5, "abcde", 5) != buf + 5 + MEMPCPY_RET ("abcde") + || memcmp (buf, "aabcdabcde", 10)) + FAIL (); + +@@ -208,7 +220,7 @@ do_test (void) + if (memcmp (buf, "aabcdefghi", 10)) + FAIL (); + +- if (mempcpy (buf + 5, "abcde", l0 + 5) != buf + 10 ++ if (MEMPCPY (buf + 5, "abcde", l0 + 5) != buf + 5 + MEMPCPY_RET ("abcde") + || memcmp (buf, "aabcdabcde", 10)) + FAIL (); + +@@ -267,7 +279,8 @@ do_test (void) + if (memcmp (a.buf1, "aabcdefghi", 10)) + FAIL (); + +- if (mempcpy (a.buf1 + 5, "abcde", l0 + 5) != a.buf1 + 10 ++ if (MEMPCPY (a.buf1 + 5, "abcde", l0 + 5) ++ != a.buf1 + 5 + MEMPCPY_RET ("abcde") + || memcmp (a.buf1, "aabcdabcde", 10)) + FAIL (); + +@@ -348,6 +361,7 @@ do_test (void) + bcopy (buf + 1, buf + 2, l0 + 9); + CHK_FAIL_END + ++#ifdef _GNU_SOURCE + CHK_FAIL_START + p = (char *) mempcpy (buf + 6, "abcde", 5); + CHK_FAIL_END +@@ -355,6 +369,7 @@ do_test (void) + CHK_FAIL_START + p = (char *) mempcpy (buf + 6, "abcde", l0 + 5); + CHK_FAIL_END ++#endif + + CHK_FAIL_START + memset (buf + 9, 'j', 2); +@@ -465,6 +480,7 @@ do_test (void) + bcopy (a.buf1 + 1, a.buf1 + 2, l0 + 9); + CHK_FAIL_END + ++#ifdef _GNU_SOURCE + CHK_FAIL_START + p = (char *) mempcpy (a.buf1 + 6, "abcde", 5); + CHK_FAIL_END +@@ -472,6 +488,7 @@ do_test (void) + CHK_FAIL_START + p = (char *) mempcpy (a.buf1 + 6, "abcde", l0 + 5); + CHK_FAIL_END ++#endif + + CHK_FAIL_START + memset (a.buf1 + 9, 'j', 2); +@@ -551,7 +568,7 @@ do_test (void) + if (wmemcmp (wbuf, L"aabcdefghi", 10)) + FAIL (); + +- if (wmempcpy (wbuf + 5, L"abcde", 5) != wbuf + 10 ++ if (WMEMPCPY (wbuf + 5, L"abcde", 5) != wbuf + 5 + WMEMPCPY_RET (L"abcde") + || wmemcmp (wbuf, L"aabcdabcde", 10)) + FAIL (); + +@@ -584,7 +601,8 @@ do_test (void) + if (wmemcmp (wbuf, L"aabcdefghi", 10)) + FAIL (); + +- if (wmempcpy (wbuf + 5, L"abcde", l0 + 5) != wbuf + 10 ++ if (WMEMPCPY (wbuf + 5, L"abcde", l0 + 5) ++ != wbuf + 5 + WMEMPCPY_RET (L"abcde") + || wmemcmp (wbuf, L"aabcdabcde", 10)) + FAIL (); + +@@ -626,7 +644,8 @@ do_test (void) + if (wmemcmp (wa.buf1, L"aabcdefghi", 10)) + FAIL (); + +- if (wmempcpy (wa.buf1 + 5, L"abcde", l0 + 5) != wa.buf1 + 10 ++ if (WMEMPCPY (wa.buf1 + 5, L"abcde", l0 + 5) ++ != wa.buf1 + 5 + WMEMPCPY_RET (L"abcde") + || wmemcmp (wa.buf1, L"aabcdabcde", 10)) + FAIL (); + +@@ -695,6 +714,7 @@ do_test (void) + wmemmove (wbuf + 2, wbuf + 1, l0 + 9); + CHK_FAIL_END + ++#ifdef _GNU_SOURCE + CHK_FAIL_START + wp = wmempcpy (wbuf + 6, L"abcde", 5); + CHK_FAIL_END +@@ -702,6 +722,7 @@ do_test (void) + CHK_FAIL_START + wp = wmempcpy (wbuf + 6, L"abcde", l0 + 5); + CHK_FAIL_END ++#endif + + CHK_FAIL_START + wmemset (wbuf + 9, L'j', 2); +@@ -769,6 +790,7 @@ do_test (void) + wmemmove (wa.buf1 + 2, wa.buf1 + 1, l0 + 9); + CHK_FAIL_END + ++#ifdef _GNU_SOURCE + CHK_FAIL_START + wp = wmempcpy (wa.buf1 + 6, L"abcde", 5); + CHK_FAIL_END +@@ -776,6 +798,7 @@ do_test (void) + CHK_FAIL_START + wp = wmempcpy (wa.buf1 + 6, L"abcde", l0 + 5); + CHK_FAIL_END ++#endif + + CHK_FAIL_START + wmemset (wa.buf1 + 9, L'j', 2); +@@ -907,6 +930,7 @@ do_test (void) + if (fprintf (fp, buf2 + 4, str5) != 7) + FAIL (); + ++#ifdef _GNU_SOURCE + char *my_ptr = NULL; + strcpy (buf2 + 2, "%n%s%n"); + /* When the format string is writable and contains %n, +@@ -936,6 +960,7 @@ do_test (void) + if (obstack_printf (&obs, "%s%n%s%n", str4, &n1, str5, &n1) != 14) + FAIL (); + obstack_free (&obs, NULL); ++#endif + + if (freopen (temp_filename, "r", stdin) == NULL) + { +@@ -983,6 +1008,7 @@ do_test (void) + + rewind (stdin); + ++#ifdef _GNU_SOURCE + if (fgets_unlocked (buf, buf_size, stdin) != buf + || memcmp (buf, "abcdefgh\n", 10)) + FAIL (); +@@ -1009,6 +1035,7 @@ do_test (void) + #endif + + rewind (stdin); ++#endif + + if (fread (buf, 1, buf_size, stdin) != buf_size + || memcmp (buf, "abcdefgh\nA", 10)) +@@ -1579,7 +1606,10 @@ do_test (void) + ret = 1; + } + +- int fd = posix_openpt (O_RDWR); ++ int fd; ++ ++#ifdef _GNU_SOURCE ++ fd = posix_openpt (O_RDWR); + if (fd != -1) + { + char enough[1000]; +@@ -1595,6 +1625,7 @@ do_test (void) + #endif + close (fd); + } ++#endif + + #if PATH_MAX > 0 + confstr (_CS_GNU_LIBC_VERSION, largebuf, sizeof (largebuf)); +@@ -1712,8 +1743,9 @@ do_test (void) + poll (fds, l0 + 2, 0); + CHK_FAIL_END + #endif ++#ifdef _GNU_SOURCE + ppoll (fds, 1, NULL, NULL); +-#if __USE_FORTIFY_LEVEL >= 1 ++# if __USE_FORTIFY_LEVEL >= 1 + CHK_FAIL_START + ppoll (fds, 2, NULL, NULL); + CHK_FAIL_END +@@ -1721,6 +1753,7 @@ do_test (void) + CHK_FAIL_START + ppoll (fds, l0 + 2, NULL, NULL); + CHK_FAIL_END ++# endif + #endif + + return ret; +diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h +index a456d1723547db70..ddfaed4dd7574cd2 100644 +--- a/posix/bits/unistd.h ++++ b/posix/bits/unistd.h +@@ -38,7 +38,7 @@ read (int __fd, void *__buf, size_t __nbytes) + __fd, __buf, __nbytes); + } + +-#ifdef __USE_UNIX98 ++#if defined __USE_UNIX98 || defined __USE_XOPEN2K8 + extern ssize_t __pread_chk (int __fd, void *__buf, size_t __nbytes, + __off_t __offset, size_t __bufsize) __wur; + extern ssize_t __pread64_chk (int __fd, void *__buf, size_t __nbytes, +diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h +index 27ec273ec41cd81c..3f86629bf8fc51a2 100644 +--- a/string/bits/string_fortified.h ++++ b/string/bits/string_fortified.h +@@ -94,7 +94,7 @@ __NTH (strcpy (char *__restrict __dest, const char *__restrict __src)) + return __builtin___strcpy_chk (__dest, __src, __glibc_objsize (__dest)); + } + +-#ifdef __USE_GNU ++#ifdef __USE_XOPEN2K8 + __fortify_function char * + __NTH (stpcpy (char *__restrict __dest, const char *__restrict __src)) + { +@@ -111,14 +111,15 @@ __NTH (strncpy (char *__restrict __dest, const char *__restrict __src, + __glibc_objsize (__dest)); + } + +-#if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6) ++#ifdef __USE_XOPEN2K8 ++# if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6) + __fortify_function char * + __NTH (stpncpy (char *__dest, const char *__src, size_t __n)) + { + return __builtin___stpncpy_chk (__dest, __src, __n, + __glibc_objsize (__dest)); + } +-#else ++# else + extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n, + size_t __destlen) __THROW; + extern char *__REDIRECT_NTH (__stpncpy_alias, (char *__dest, const char *__src, +@@ -132,6 +133,7 @@ __NTH (stpncpy (char *__dest, const char *__src, size_t __n)) + return __stpncpy_chk (__dest, __src, __n, __bos (__dest)); + return __stpncpy_alias (__dest, __src, __n); + } ++# endif + #endif + + +diff --git a/support/xsignal.h b/support/xsignal.h +index 9ab8d1bfddf6c598..fae6108a522ae5fe 100644 +--- a/support/xsignal.h ++++ b/support/xsignal.h +@@ -28,7 +28,9 @@ __BEGIN_DECLS + terminate the process on error. */ + + void xraise (int sig); ++#ifdef _GNU_SOURCE + sighandler_t xsignal (int sig, sighandler_t handler); ++#endif + void xsigaction (int sig, const struct sigaction *newact, + struct sigaction *oldact); + +diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h +index f82bba481981e4fb..5c68979e96a504b4 100644 +--- a/wcsmbs/bits/wchar2.h ++++ b/wcsmbs/bits/wchar2.h +@@ -457,7 +457,7 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + } + + +-#ifdef __USE_GNU ++#ifdef __USE_XOPEN2K8 + extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, + const char **__restrict __src, size_t __nmc, + size_t __len, mbstate_t *__restrict __ps, diff --git a/SOURCES/glibc-rh2063712.patch b/SOURCES/glibc-rh2063712.patch new file mode 100644 index 0000000..b66fce4 --- /dev/null +++ b/SOURCES/glibc-rh2063712.patch @@ -0,0 +1,208 @@ +This is a downstream rework of this upstream patch: + + [PATCH v2 2/2] nss: Protect against errno changes in function lookup (bug 28953) + + +The NSS module loading code has been rewritten upstream, which is why +only the test can be reused. NSS_DECLARE_MODULE_FUNCTIONS does not yet +exist downstream, so this part had to be skipped. + +diff --git a/nss/Makefile b/nss/Makefile +index d5c28a6b5ed3661c..e8a7d9c7b3cefcdf 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -59,7 +59,8 @@ tests = test-netdb test-digits-dots tst-nss-getpwent bug17079 \ + tst-nss-test2 \ + tst-nss-test3 \ + tst-nss-test4 \ +- tst-nss-test5 ++ tst-nss-test5 \ ++ tst-nss-test_errno + xtests = bug-erange + + tests-container = \ +@@ -130,7 +131,7 @@ routines += $(libnss_files-routines) + static-only-routines += $(libnss_files-routines) + tests-static += tst-nss-static + endif +-extra-test-objs += nss_test1.os nss_test2.os ++extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os + + include ../Rules + +@@ -166,10 +167,13 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver + + libof-nss_test1 = extramodules + libof-nss_test2 = extramodules ++libof-nss_test_errno = extramodules + $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) + $(build-module) ++$(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) ++ $(build-module) + $(objpfx)nss_test2.os : nss_test1.c + ifdef libnss_test1.so-version + $(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so +@@ -179,9 +183,13 @@ ifdef libnss_test2.so-version + $(objpfx)/libnss_test2.so$(libnss_test2.so-version): $(objpfx)/libnss_test2.so + $(make-link) + endif ++$(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ ++ $(objpfx)/libnss_test_errno.so ++ $(make-link) + $(patsubst %,$(objpfx)%.out,$(tests)) : \ + $(objpfx)/libnss_test1.so$(libnss_test1.so-version) \ +- $(objpfx)/libnss_test2.so$(libnss_test2.so-version) ++ $(objpfx)/libnss_test2.so$(libnss_test2.so-version) \ ++ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) + + ifeq (yes,$(have-thread-library)) + $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +diff --git a/nss/nss_test_errno.c b/nss/nss_test_errno.c +new file mode 100644 +index 0000000000000000..ca75c890aa057869 +--- /dev/null ++++ b/nss/nss_test_errno.c +@@ -0,0 +1,53 @@ ++/* NSS service provider with errno clobber. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ /* An arbitrary error code which is otherwise not used. */ ++ errno = ELIBBAD; ++} ++ ++/* Lookup functions for pwd follow that do not return any data. */ ++ ++enum nss_status ++_nss_test_errno_setpwent (int stayopen) ++{ ++ setenv ("_nss_test_errno_setpwent", "yes", 1); ++ return NSS_STATUS_SUCCESS; ++} ++ ++enum nss_status ++_nss_test_errno_getpwent_r (struct passwd *result, ++ char *buffer, size_t size, int *errnop) ++{ ++ setenv ("_nss_test_errno_getpwent_r", "yes", 1); ++ return NSS_STATUS_NOTFOUND; ++} ++ ++enum nss_status ++_nss_test_errno_endpwent (void) ++{ ++ setenv ("_nss_test_errno_endpwent", "yes", 1); ++ return NSS_STATUS_SUCCESS; ++} +diff --git a/nss/nsswitch.c b/nss/nsswitch.c +index 17adf1ef03f93d60..e59ab674e0426b26 100644 +--- a/nss/nsswitch.c ++++ b/nss/nsswitch.c +@@ -401,6 +401,7 @@ void * + __nss_lookup_function (service_user *ni, const char *fct_name) + { + void **found, *result; ++ int saved_errno = errno; + + /* We now modify global data. Protect it. */ + __libc_lock_lock (lock); +@@ -523,6 +524,8 @@ __nss_lookup_function (service_user *ni, const char *fct_name) + /* Remove the lock. */ + __libc_lock_unlock (lock); + ++ __set_errno (saved_errno); ++ + return result; + } + libc_hidden_def (__nss_lookup_function) +diff --git a/nss/tst-nss-test_errno.c b/nss/tst-nss-test_errno.c +new file mode 100644 +index 0000000000000000..d2c42dd363a38b0e +--- /dev/null ++++ b/nss/tst-nss-test_errno.c +@@ -0,0 +1,61 @@ ++/* getpwent failure when dlopen clobbers errno (bug 28953). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ __nss_configure_lookup ("passwd", "files test_errno"); ++ ++ errno = 0; ++ setpwent (); ++ TEST_COMPARE (errno, 0); ++ ++ bool root_seen = false; ++ while (true) ++ { ++ errno = 0; ++ struct passwd *e = getpwent (); ++ if (e == NULL) ++ break; ++ if (strcmp (e->pw_name, "root")) ++ root_seen = true; ++ } ++ ++ TEST_COMPARE (errno, 0); ++ TEST_VERIFY (root_seen); ++ ++ errno = 0; ++ endpwent (); ++ TEST_COMPARE (errno, 0); ++ ++ TEST_COMPARE_STRING (getenv ("_nss_test_errno_setpwent"), "yes"); ++ TEST_COMPARE_STRING (getenv ("_nss_test_errno_getpwent_r"), "yes"); ++ TEST_COMPARE_STRING (getenv ("_nss_test_errno_endpwent"), "yes"); ++ ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-rh2065588-1.patch b/SOURCES/glibc-rh2065588-1.patch new file mode 100644 index 0000000..3b4db3f --- /dev/null +++ b/SOURCES/glibc-rh2065588-1.patch @@ -0,0 +1,253 @@ +commit 2a973ab7f1a6f6cd9be1c7257fd7b5d331515eab +Author: Adhemerval Zanella +Date: Wed Sep 12 10:30:46 2018 -0300 + + posix: Add internal symbols for posix_spawn interface + + This patch adds internal hidden definition for mostly of the posix_spawn + function so it can be used internally on both popen and system + implementations. + + Checked on x86_64-linux-gnu. + + * include/spawn.h (__posix_spawn, posix_spawn_file_actions_addclose, + __posix_spawn_file_actions_adddup2, __posix_spawn_file_actions_destroy, + __posix_spawn_file_actions_init, __posix_spawnattr_init, + __posix_spawnattr_destroy, __posix_spawnattr_setflags, + __posix_spawnattr_setsigdefault, __posix_spawnattr_setsigmask): New + prototype. + * posix/spawn.c (__posix_spawn): Add libc_hidden_def. + * posix/spawn_faction_addclose.c + (__posix_spawn_file_actions_addclose): Add hidden definition. + * posix/spawn_faction_adddup2.c + (__posix_spawn_file_actions_adddup2): Likewise. + * posix/spawn_faction_destroy.c + (__posix_spawn_file_actions_destroy): Likewise. + * posix/spawn_faction_init.c (__posix_spawn_file_actions_init): + Likewise. + * posix/spawnattr_destroy.c (__posix_spawnattr_destroy): Likewise. + * posix/spawnattr_init.c (__posix_spawnattr_init): Likewise. + * posix/spawnattr_setdefault.c (__posix_spawnattr_setsigdefault): + Likewise. + * posix/spawnattr_setflags.c (__posix_spawnattr_setflags): Likewise. + * posix/spawnattr_setsigmask.c (__posix_spawnattr_setsigmask): + Likewise. + +diff --git a/include/spawn.h b/include/spawn.h +index a6c7a8adc361927e..7fdd965bd780f8de 100644 +--- a/include/spawn.h ++++ b/include/spawn.h +@@ -1 +1,36 @@ ++#ifndef _SPAWN_H + #include ++ ++# ifndef _ISOMAC ++__typeof (posix_spawn) __posix_spawn; ++libc_hidden_proto (__posix_spawn) ++ ++__typeof (posix_spawn_file_actions_addclose) ++ __posix_spawn_file_actions_addclose attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_adddup2) ++ __posix_spawn_file_actions_adddup2 attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_destroy) ++ __posix_spawn_file_actions_destroy attribute_hidden; ++ ++__typeof (posix_spawn_file_actions_init) __posix_spawn_file_actions_init ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_init) __posix_spawnattr_init ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_destroy) __posix_spawnattr_destroy ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setflags) __posix_spawnattr_setflags ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setsigdefault) __posix_spawnattr_setsigdefault ++ attribute_hidden; ++ ++__typeof (posix_spawnattr_setsigmask) __posix_spawnattr_setsigmask ++ attribute_hidden; ++ ++# endif /* !_ISOMAC */ ++#endif /* spawn.h */ +diff --git a/posix/spawn.c b/posix/spawn.c +index 51f67b2755bd4949..a82f1c84e299f018 100644 +--- a/posix/spawn.c ++++ b/posix/spawn.c +@@ -30,6 +30,7 @@ __posix_spawn (pid_t *pid, const char *path, + return __spawni (pid, path, file_actions, attrp, argv, envp, 0); + } + versioned_symbol (libc, __posix_spawn, posix_spawn, GLIBC_2_15); ++libc_hidden_def (__posix_spawn) + + + #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) +diff --git a/posix/spawn_faction_addclose.c b/posix/spawn_faction_addclose.c +index 21081e19b55db44c..e1fafe438cf15c91 100644 +--- a/posix/spawn_faction_addclose.c ++++ b/posix/spawn_faction_addclose.c +@@ -24,8 +24,8 @@ + /* Add an action to FILE-ACTIONS which tells the implementation to call + `close' for the given file descriptor during the `spawn' call. */ + int +-posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, +- int fd) ++__posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, ++ int fd) + { + struct __spawn_action *rec; + +@@ -48,3 +48,5 @@ posix_spawn_file_actions_addclose (posix_spawn_file_actions_t *file_actions, + + return 0; + } ++weak_alias (__posix_spawn_file_actions_addclose, ++ posix_spawn_file_actions_addclose) +diff --git a/posix/spawn_faction_adddup2.c b/posix/spawn_faction_adddup2.c +index 363bc29ae502bd60..371b1de3e6f1979a 100644 +--- a/posix/spawn_faction_adddup2.c ++++ b/posix/spawn_faction_adddup2.c +@@ -24,8 +24,8 @@ + /* Add an action to FILE-ACTIONS which tells the implementation to call + `dup2' for the given file descriptors during the `spawn' call. */ + int +-posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, +- int fd, int newfd) ++__posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, ++ int fd, int newfd) + { + struct __spawn_action *rec; + +@@ -49,3 +49,5 @@ posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *file_actions, + + return 0; + } ++weak_alias (__posix_spawn_file_actions_adddup2, ++ posix_spawn_file_actions_adddup2) +diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c +index 46061ee3473d4475..2a2de4e41d6bd6d0 100644 +--- a/posix/spawn_faction_destroy.c ++++ b/posix/spawn_faction_destroy.c +@@ -22,7 +22,7 @@ + + /* Deallocate the file actions. */ + int +-posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) ++__posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) + { + /* Free the paths in the open actions. */ + for (int i = 0; i < file_actions->__used; ++i) +@@ -44,3 +44,5 @@ posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions) + free (file_actions->__actions); + return 0; + } ++weak_alias (__posix_spawn_file_actions_destroy, ++ posix_spawn_file_actions_destroy) +diff --git a/posix/spawn_faction_init.c b/posix/spawn_faction_init.c +index ddb42e6a77ba41ec..98432067c645021e 100644 +--- a/posix/spawn_faction_init.c ++++ b/posix/spawn_faction_init.c +@@ -45,9 +45,10 @@ __posix_spawn_file_actions_realloc (posix_spawn_file_actions_t *file_actions) + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions) ++__posix_spawn_file_actions_init (posix_spawn_file_actions_t *file_actions) + { + /* Simply clear all the elements. */ + memset (file_actions, '\0', sizeof (*file_actions)); + return 0; + } ++weak_alias (__posix_spawn_file_actions_init, posix_spawn_file_actions_init) +diff --git a/posix/spawnattr_destroy.c b/posix/spawnattr_destroy.c +index 603e00fffefae2bf..043386778588913a 100644 +--- a/posix/spawnattr_destroy.c ++++ b/posix/spawnattr_destroy.c +@@ -19,8 +19,9 @@ + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawnattr_destroy (posix_spawnattr_t *attr) ++__posix_spawnattr_destroy (posix_spawnattr_t *attr) + { + /* Nothing to do in the moment. */ + return 0; + } ++weak_alias (__posix_spawnattr_destroy, posix_spawnattr_destroy) +diff --git a/posix/spawnattr_init.c b/posix/spawnattr_init.c +index bab464e62bdf7889..4e1218ab44e3f779 100644 +--- a/posix/spawnattr_init.c ++++ b/posix/spawnattr_init.c +@@ -20,7 +20,7 @@ + + /* Initialize data structure for file attribute for `spawn' call. */ + int +-posix_spawnattr_init (posix_spawnattr_t *attr) ++__posix_spawnattr_init (posix_spawnattr_t *attr) + { + /* All elements have to be initialized to the default values which + is generally zero. */ +@@ -28,3 +28,4 @@ posix_spawnattr_init (posix_spawnattr_t *attr) + + return 0; + } ++weak_alias (__posix_spawnattr_init, posix_spawnattr_init) +diff --git a/posix/spawnattr_setdefault.c b/posix/spawnattr_setdefault.c +index c77cda59be3dda20..174bcfa423dc5666 100644 +--- a/posix/spawnattr_setdefault.c ++++ b/posix/spawnattr_setdefault.c +@@ -20,11 +20,12 @@ + + /* Set signal mask for signals with default handling in ATTR to SIGDEFAULT. */ + int +-posix_spawnattr_setsigdefault (posix_spawnattr_t *attr, +- const sigset_t *sigdefault) ++__posix_spawnattr_setsigdefault (posix_spawnattr_t *attr, ++ const sigset_t *sigdefault) + { + /* Copy the sigset_t data to the user buffer. */ + memcpy (&attr->__sd, sigdefault, sizeof (sigset_t)); + + return 0; + } ++weak_alias (__posix_spawnattr_setsigdefault, posix_spawnattr_setsigdefault) +diff --git a/posix/spawnattr_setflags.c b/posix/spawnattr_setflags.c +index cf9a60181dc91ccd..0a42e94770224a94 100644 +--- a/posix/spawnattr_setflags.c ++++ b/posix/spawnattr_setflags.c +@@ -30,7 +30,7 @@ + + /* Store flags in the attribute structure. */ + int +-posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) ++__posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) + { + /* Check no invalid bits are set. */ + if (flags & ~ALL_FLAGS) +@@ -41,3 +41,4 @@ posix_spawnattr_setflags (posix_spawnattr_t *attr, short int flags) + + return 0; + } ++weak_alias (__posix_spawnattr_setflags, posix_spawnattr_setflags) +diff --git a/posix/spawnattr_setsigmask.c b/posix/spawnattr_setsigmask.c +index 7ae81ad47025db6f..12c0111af441dd13 100644 +--- a/posix/spawnattr_setsigmask.c ++++ b/posix/spawnattr_setsigmask.c +@@ -20,7 +20,7 @@ + + /* Set signal mask for the new process in ATTR to SIGMASK. */ + int +-posix_spawnattr_setsigmask (posix_spawnattr_t *attr, ++__posix_spawnattr_setsigmask (posix_spawnattr_t *attr, + const sigset_t *sigmask) + { + /* Copy the sigset_t data to the user buffer. */ +@@ -28,3 +28,4 @@ posix_spawnattr_setsigmask (posix_spawnattr_t *attr, + + return 0; + } ++weak_alias (__posix_spawnattr_setsigmask, posix_spawnattr_setsigmask) diff --git a/SOURCES/glibc-rh2065588-10.patch b/SOURCES/glibc-rh2065588-10.patch new file mode 100644 index 0000000..3016994 --- /dev/null +++ b/SOURCES/glibc-rh2065588-10.patch @@ -0,0 +1,21 @@ +commit 5fce0e095bc413f908f472074c2235198cd76bf4 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:36:23 2020 -0300 + + support/shell-container.c: Return 127 if execve fails + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index e87ac5cf1baa84e5..e9eea64bca7e949d 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -238,7 +238,7 @@ run_command_array (char **argv) + + fprintf (stderr, "sh: execing %s failed: %s", + argv[0], strerror (errno)); +- exit (1); ++ exit (127); + } + + waitpid (pid, &status, 0); diff --git a/SOURCES/glibc-rh2065588-11.patch b/SOURCES/glibc-rh2065588-11.patch new file mode 100644 index 0000000..a1ef4a7 --- /dev/null +++ b/SOURCES/glibc-rh2065588-11.patch @@ -0,0 +1,39 @@ +commit 5a5a3a3234bc220a5192d620e0cbc5360da46f14 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:40:36 2020 -0300 + + support/shell-container.c: Add builtin exit + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index e9eea64bca7e949d..aeaf6d2733abce61 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -135,6 +135,18 @@ copy_func (char **argv) + + } + ++/* Emulate the 'exit' builtin. The exit value is optional. */ ++static int ++exit_func (char **argv) ++{ ++ int exit_val = 0; ++ ++ if (argv[0] != 0) ++ exit_val = atoi (argv[0]) & 0xff; ++ exit (exit_val); ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -143,6 +155,7 @@ static struct { + { "true", true_func }, + { "echo", echo_func }, + { "cp", copy_func }, ++ { "exit", exit_func }, + { NULL, NULL } + }; + diff --git a/SOURCES/glibc-rh2065588-12.patch b/SOURCES/glibc-rh2065588-12.patch new file mode 100644 index 0000000..7f4223f --- /dev/null +++ b/SOURCES/glibc-rh2065588-12.patch @@ -0,0 +1,60 @@ +commit 1c17100c43c0913ec94f3bcc966bf3792236c690 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:47:13 2020 -0300 + + support/shell-container.c: Add builtin kill + + No options supported. + + Reviewed-by: DJ Delorie + +diff --git a/support/shell-container.c b/support/shell-container.c +index aeaf6d2733abce61..3869e14683fb74dd 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -147,6 +147,25 @@ exit_func (char **argv) + return 0; + } + ++/* Emulate the "/bin/kill" command. Options are ignored. */ ++static int ++kill_func (char **argv) ++{ ++ int signum = SIGTERM; ++ int i; ++ ++ for (i = 0; argv[i]; i++) ++ { ++ pid_t pid; ++ if (strcmp (argv[i], "$$") == 0) ++ pid = getpid (); ++ else ++ pid = atoi (argv[i]); ++ kill (pid, signum); ++ } ++ return 0; ++} ++ + /* This is a list of all the built-in commands we understand. */ + static struct { + const char *name; +@@ -156,6 +175,7 @@ static struct { + { "echo", echo_func }, + { "cp", copy_func }, + { "exit", exit_func }, ++ { "kill", kill_func }, + { NULL, NULL } + }; + +@@ -264,6 +284,11 @@ run_command_array (char **argv) + if (rv) + exit (rv); + } ++ else if (WIFSIGNALED (status)) ++ { ++ int sig = WTERMSIG (status); ++ raise (sig); ++ } + else + exit (1); + } diff --git a/SOURCES/glibc-rh2065588-13.patch b/SOURCES/glibc-rh2065588-13.patch new file mode 100644 index 0000000..e4e9d70 --- /dev/null +++ b/SOURCES/glibc-rh2065588-13.patch @@ -0,0 +1,66 @@ +commit 75fe6d1a1620d84e0e487868feba9b2c0f109610 +Author: Siddhesh Poyarekar +Date: Wed May 12 10:13:41 2021 +0530 + + support: Close fds in copy_func + + copy_func may leave file descriptors open on error, so close them on + function exit. + +diff --git a/support/shell-container.c b/support/shell-container.c +index 3869e14683fb74dd..f0a9814ae230d167 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -93,8 +93,9 @@ copy_func (char **argv) + { + char *sname = argv[0]; + char *dname = argv[1]; +- int sfd, dfd; ++ int sfd = -1, dfd = -1; + struct stat st; ++ int ret = 1; + + sfd = open (sname, O_RDONLY); + if (sfd < 0) +@@ -108,7 +109,7 @@ copy_func (char **argv) + { + fprintf (stderr, "cp: unable to fstat %s: %s\n", + sname, strerror (errno)); +- return 1; ++ goto out; + } + + dfd = open (dname, O_WRONLY | O_TRUNC | O_CREAT, 0600); +@@ -116,22 +117,26 @@ copy_func (char **argv) + { + fprintf (stderr, "cp: unable to open %s for writing: %s\n", + dname, strerror (errno)); +- return 1; ++ goto out; + } + + if (support_copy_file_range (sfd, 0, dfd, 0, st.st_size, 0) != st.st_size) + { + fprintf (stderr, "cp: cannot copy file %s to %s: %s\n", + sname, dname, strerror (errno)); +- return 1; ++ goto out; + } + +- close (sfd); +- close (dfd); +- ++ ret = 0; + chmod (dname, st.st_mode & 0777); + +- return 0; ++out: ++ if (sfd >= 0) ++ close (sfd); ++ if (dfd >= 0) ++ close (dfd); ++ ++ return ret; + + } + diff --git a/SOURCES/glibc-rh2065588-2.patch b/SOURCES/glibc-rh2065588-2.patch new file mode 100644 index 0000000..c671cf9 --- /dev/null +++ b/SOURCES/glibc-rh2065588-2.patch @@ -0,0 +1,231 @@ +commit 14d0e87d9b8caaa2eca7ca81f1189596671fe4fb +Author: Adhemerval Zanella +Date: Wed Sep 12 10:32:05 2018 -0300 + + posix: Use posix_spawn on popen + + This patch uses posix_spawn on popen instead of fork and execl. On Linux + this has the advantage of much lower memory consumption (usually 32 Kb + minimum for the mmap stack area). + + Two issues are also fixed with this change: + + * BZ#17490: although POSIX pthread_atfork description only list 'fork' + as the function that should execute the atfork handlers, popen + description states that: + + '[...] shall be *as if* a child process were created within the popen() + call using the fork() function [...]' + + Other libc/system seems to follow the idea atfork handlers should not be + executed for popen: + + libc/system | run atfork handles | notes + ------------|----------------------|--------------------------------------- + Freebsd | no | uses vfork + Solaris 11 | no | + MacOSX 11 | no | implemented through posix_spawn syscall + ------------|----------------------|---------------------------------------- + + Similar to posix_spawn and system, popen idea is to spawn a different + binary so all the POSIX rationale to run the atfork handlers to avoid + internal process inconsistency is not really required and in some cases + might be unsafe. + + * BZ#22834: the described scenario, where the forked process might access + invalid memory due an inconsistent state in multithreaded environment, + should not happen because posix_spawn does not access the affected + data structure (proc_file_chain). + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + [BZ #22834] + [BZ #17490] + * NEWS: Add new semantic for atfork with popen and system. + * libio/iopopen.c (_IO_new_proc_open): use posix_spawn instead of + fork and execl. + +diff --git a/libio/iopopen.c b/libio/iopopen.c +index 2eff45b4c80b5cd6..c768295180fdf809 100644 +--- a/libio/iopopen.c ++++ b/libio/iopopen.c +@@ -34,7 +34,8 @@ + #include + #include + #include +-#include ++#include ++#include + + struct _IO_proc_file + { +@@ -59,13 +60,60 @@ unlock (void *not_used) + } + #endif + ++/* POSIX states popen shall ensure that any streams from previous popen() ++ calls that remain open in the parent process should be closed in the new ++ child process. ++ To avoid a race-condition between checking which file descriptors need to ++ be close (by transversing the proc_file_chain list) and the insertion of a ++ new one after a successful posix_spawn this function should be called ++ with proc_file_chain_lock acquired. */ ++static bool ++spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command, ++ int do_cloexec, int pipe_fds[2], int parent_end, int child_end, ++ int child_pipe_fd) ++{ ++ ++ for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next) ++ { ++ int fd = _IO_fileno ((FILE *) p); ++ ++ /* If any stream from previous popen() calls has fileno ++ child_pipe_fd, it has been already closed by the adddup2 action ++ above. */ ++ if (fd != child_pipe_fd ++ && __posix_spawn_file_actions_addclose (fa, fd) != 0) ++ return false; ++ } ++ ++ if (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0, ++ (char *const[]){ (char*) "sh", (char*) "-c", ++ (char *) command, NULL }, __environ) != 0) ++ return false; ++ ++ __close_nocancel (pipe_fds[child_end]); ++ ++ if (!do_cloexec) ++ /* Undo the effects of the pipe2 call which set the ++ close-on-exec flag. */ ++ __fcntl (pipe_fds[parent_end], F_SETFD, 0); ++ ++ _IO_fileno (fp) = pipe_fds[parent_end]; ++ ++ ((_IO_proc_file *) fp)->next = proc_file_chain; ++ proc_file_chain = (_IO_proc_file *) fp; ++ ++ return true; ++} ++ + FILE * + _IO_new_proc_open (FILE *fp, const char *command, const char *mode) + { + int read_or_write; ++ /* These are indexes for pipe_fds. */ + int parent_end, child_end; + int pipe_fds[2]; +- pid_t child_pid; ++ int child_pipe_fd; ++ bool spawn_ok; + + int do_read = 0; + int do_write = 0; +@@ -108,72 +156,62 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode) + + if (do_read) + { +- parent_end = pipe_fds[0]; +- child_end = pipe_fds[1]; ++ parent_end = 0; ++ child_end = 1; + read_or_write = _IO_NO_WRITES; ++ child_pipe_fd = 1; + } + else + { +- parent_end = pipe_fds[1]; +- child_end = pipe_fds[0]; ++ parent_end = 1; ++ child_end = 0; + read_or_write = _IO_NO_READS; ++ child_pipe_fd = 0; + } + +- ((_IO_proc_file *) fp)->pid = child_pid = __fork (); +- if (child_pid == 0) +- { +- int child_std_end = do_read ? 1 : 0; +- struct _IO_proc_file *p; +- +- if (child_end != child_std_end) +- __dup2 (child_end, child_std_end); +- else +- /* The descriptor is already the one we will use. But it must +- not be marked close-on-exec. Undo the effects. */ +- __fcntl (child_end, F_SETFD, 0); +- /* POSIX.2: "popen() shall ensure that any streams from previous +- popen() calls that remain open in the parent process are closed +- in the new child process." */ +- for (p = proc_file_chain; p; p = p->next) +- { +- int fd = _IO_fileno ((FILE *) p); ++ posix_spawn_file_actions_t fa; ++ /* posix_spawn_file_actions_init does not fail. */ ++ __posix_spawn_file_actions_init (&fa); + +- /* If any stream from previous popen() calls has fileno +- child_std_end, it has been already closed by the dup2 syscall +- above. */ +- if (fd != child_std_end) +- __close_nocancel (fd); +- } +- +- execl ("/bin/sh", "sh", "-c", command, (char *) 0); +- _exit (127); +- } +- __close_nocancel (child_end); +- if (child_pid < 0) ++ /* The descriptor is already the one the child will use. In this case ++ it must be moved to another one otherwise, there is no safe way to ++ remove the close-on-exec flag in the child without creating a FD leak ++ race in the parent. */ ++ if (pipe_fds[child_end] == child_pipe_fd) + { +- __close_nocancel (parent_end); +- return NULL; ++ int tmp = __fcntl (child_pipe_fd, F_DUPFD_CLOEXEC, 0); ++ if (tmp < 0) ++ goto spawn_failure; ++ __close_nocancel (pipe_fds[child_end]); ++ pipe_fds[child_end] = tmp; + } + +- if (!do_cloexec) +- /* Undo the effects of the pipe2 call which set the +- close-on-exec flag. */ +- __fcntl (parent_end, F_SETFD, 0); ++ if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end], ++ child_pipe_fd) != 0) ++ goto spawn_failure; + +- _IO_fileno (fp) = parent_end; +- +- /* Link into proc_file_chain. */ + #ifdef _IO_MTSAFE_IO + _IO_cleanup_region_start_noarg (unlock); + _IO_lock_lock (proc_file_chain_lock); + #endif +- ((_IO_proc_file *) fp)->next = proc_file_chain; +- proc_file_chain = (_IO_proc_file *) fp; ++ spawn_ok = spawn_process (&fa, fp, command, do_cloexec, pipe_fds, ++ parent_end, child_end, child_pipe_fd); + #ifdef _IO_MTSAFE_IO + _IO_lock_unlock (proc_file_chain_lock); + _IO_cleanup_region_end (0); + #endif + ++ __posix_spawn_file_actions_destroy (&fa); ++ ++ if (!spawn_ok) ++ { ++ spawn_failure: ++ __close_nocancel (pipe_fds[child_end]); ++ __close_nocancel (pipe_fds[parent_end]); ++ __set_errno (ENOMEM); ++ return NULL; ++ } ++ + _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES); + return fp; + } diff --git a/SOURCES/glibc-rh2065588-3.patch b/SOURCES/glibc-rh2065588-3.patch new file mode 100644 index 0000000..d168d88 --- /dev/null +++ b/SOURCES/glibc-rh2065588-3.patch @@ -0,0 +1,527 @@ +commit 5fb7fc96350575c9adb1316833e48ca11553be49 +Author: Adhemerval Zanella +Date: Wed Oct 24 16:29:38 2018 -0300 + + posix: Use posix_spawn on system + + This patch uses posix_spawn on system implementation. On Linux this has + the advantage of much lower memory consumption (usually 32 Kb minimum for + the mmap stack area). + + Although POSIX does not require, glibc system implementation aims to be + thread and cancellation safe. The cancellation code is moved to generic + implementation and enabled iff SIGCANCEL is defined (similar on how the + cancellation handler is enabled on nptl-init.c). + + Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu, + arm-linux-gnueabihf, and powerpc64le-linux-gnu. + + * sysdeps/unix/sysv/linux/spawni.c (__spawni_child): Use + __sigismember instead of sigismember. + * sysdeps/posix/system.c [SIGCANCEL] (cancel_handler_args, + cancel_handler): New definitions. + (CLEANUP_HANDLER, CLEANUP_RESET): Likewise. + (DO_LOCK, DO_UNLOCK, INIT_LOCK, ADD_REF, SUB_REF): Remove. + (do_system): Use posix_spawn instead of fork and execl and remove + reentracy code. + * sysdeps/generic/not-errno.h (__kill_noerrno): New prototype. + * sysdeps/unix/sysv/linux/not-errno.h (__kill_noerrno): Likewise. + * sysdeps/unix/sysv/linux/ia64/system.c: Remove file. + * sysdeps/unix/sysv/linux/s390/system.c: Likewise. + * sysdeps/unix/sysv/linux/sparc/system.c: Likewise. + * sysdeps/unix/sysv/linux/system.c: Likewise. + +diff --git a/sysdeps/generic/not-errno.h b/sysdeps/generic/not-errno.h +index 93617a3266fd4aad..0fd66b5c5ed82315 100644 +--- a/sysdeps/generic/not-errno.h ++++ b/sysdeps/generic/not-errno.h +@@ -17,3 +17,5 @@ + . */ + + extern __typeof (__access) __access_noerrno attribute_hidden; ++ ++extern __typeof (__kill) __kill_noerrno attribute_hidden; +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index d7594436ed59906f..8a51a6b9919ec39b 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -17,20 +17,36 @@ + + #include + #include +-#include + #include + #include ++#include ++#include ++#include + #include + #include +-#include +-#include +-#include ++#include + ++#include ++#include ++#include ++#include + + #define SHELL_PATH "/bin/sh" /* Path of the shell. */ + #define SHELL_NAME "sh" /* Name to give it. */ + + ++/* This system implementation aims to be thread-safe, which requires to ++ restore the signal dispositions for SIGINT and SIGQUIT correctly and to ++ deal with cancellation by terminating the child process. ++ ++ The signal disposition restoration on the single-thread case is ++ straighfoward. For multithreaded case, a reference-counter with a lock ++ is used, so the first thread will set the SIGINT/SIGQUIT dispositions and ++ last thread will restore them. ++ ++ Cancellation handling is done with thread cancellation clean-up handlers ++ on waitpid call. */ ++ + #ifdef _LIBC_REENTRANT + static struct sigaction intr, quit; + static int sa_refcntr; +@@ -50,17 +66,45 @@ __libc_lock_define_initialized (static, lock); + #endif + + ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++struct cancel_handler_args ++{ ++ struct sigaction *quit; ++ struct sigaction *intr; ++ pid_t pid; ++}; ++ ++static void ++cancel_handler (void *arg) ++{ ++ struct cancel_handler_args *args = (struct cancel_handler_args *) (arg); ++ ++ __kill_noerrno (args->pid, SIGKILL); ++ ++ TEMP_FAILURE_RETRY (__waitpid_nocancel (args->pid, NULL, 0)); ++ ++ DO_LOCK (); ++ if (SUB_REF () == 0) ++ { ++ __sigaction (SIGQUIT, args->quit, NULL); ++ __sigaction (SIGINT, args->intr, NULL); ++ } ++ DO_UNLOCK (); ++} ++#endif ++ + /* Execute LINE as a shell command, returning its status. */ + static int + do_system (const char *line) + { +- int status, save; ++ int status; + pid_t pid; + struct sigaction sa; + #ifndef _LIBC_REENTRANT + struct sigaction intr, quit; + #endif + sigset_t omask; ++ sigset_t reset; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; +@@ -69,105 +113,72 @@ do_system (const char *line) + DO_LOCK (); + if (ADD_REF () == 0) + { +- if (__sigaction (SIGINT, &sa, &intr) < 0) +- { +- (void) SUB_REF (); +- goto out; +- } +- if (__sigaction (SIGQUIT, &sa, &quit) < 0) +- { +- save = errno; +- (void) SUB_REF (); +- goto out_restore_sigint; +- } ++ /* sigaction can not fail with SIGINT/SIGQUIT used with SIG_IGN. */ ++ __sigaction (SIGINT, &sa, &intr); ++ __sigaction (SIGQUIT, &sa, &quit); + } + DO_UNLOCK (); + +- /* We reuse the bitmap in the 'sa' structure. */ + __sigaddset (&sa.sa_mask, SIGCHLD); +- save = errno; +- if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) ++ /* sigprocmask can not fail with SIG_BLOCK used with valid input ++ arguments. */ ++ __sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask); ++ ++ __sigemptyset (&reset); ++ if (intr.sa_handler != SIG_IGN) ++ __sigaddset(&reset, SIGINT); ++ if (quit.sa_handler != SIG_IGN) ++ __sigaddset(&reset, SIGQUIT); ++ ++ posix_spawnattr_t spawn_attr; ++ /* None of the posix_spawnattr_* function returns an error, including ++ posix_spawnattr_setflags for the follow specific usage (using valid ++ flags). */ ++ __posix_spawnattr_init (&spawn_attr); ++ __posix_spawnattr_setsigmask (&spawn_attr, &omask); ++ __posix_spawnattr_setsigdefault (&spawn_attr, &reset); ++ __posix_spawnattr_setflags (&spawn_attr, ++ POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); ++ ++ status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, ++ (char *const[]){ (char*) SHELL_NAME, ++ (char*) "-c", ++ (char *) line, NULL }, ++ __environ); ++ __posix_spawnattr_destroy (&spawn_attr); ++ ++ if (status == 0) + { +-#ifndef _LIBC +- if (errno == ENOSYS) +- __set_errno (save); +- else +-#endif +- { +- DO_LOCK (); +- if (SUB_REF () == 0) +- { +- save = errno; +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- out_restore_sigint: +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- __set_errno (save); +- } +- out: +- DO_UNLOCK (); +- return -1; +- } +- } +- +-#ifdef CLEANUP_HANDLER +- CLEANUP_HANDLER; +-#endif +- +-#ifdef FORK +- pid = FORK (); +-#else +- pid = __fork (); ++ /* Cancellation results in cleanup handlers running as exceptions in ++ the block where they were installed, so it is safe to reference ++ stack variable allocate in the broader scope. */ ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++ struct cancel_handler_args cancel_args = ++ { ++ .quit = &quit, ++ .intr = &intr, ++ .pid = pid ++ }; ++ __libc_cleanup_region_start (1, cancel_handler, &cancel_args); + #endif +- if (pid == (pid_t) 0) +- { +- /* Child side. */ +- const char *new_argv[4]; +- new_argv[0] = SHELL_NAME; +- new_argv[1] = "-c"; +- new_argv[2] = line; +- new_argv[3] = NULL; +- +- /* Restore the signals. */ +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); +- INIT_LOCK (); +- +- /* Exec the shell. */ +- (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); +- _exit (127); +- } +- else if (pid < (pid_t) 0) +- /* The fork failed. */ +- status = -1; +- else +- /* Parent side. */ +- { + /* Note the system() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not + have to do anything here. */ + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid) + status = -1; +- } +- +-#ifdef CLEANUP_HANDLER +- CLEANUP_RESET; ++#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL) ++ __libc_cleanup_region_end (0); + #endif ++ } + +- save = errno; + DO_LOCK (); +- if ((SUB_REF () == 0 +- && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL) +- | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) +- || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) ++ if (SUB_REF () == 0) + { +-#ifndef _LIBC +- /* glibc cannot be used on systems without waitpid. */ +- if (errno == ENOSYS) +- __set_errno (save); +- else +-#endif +- status = -1; ++ /* sigaction can not fail with SIGINT/SIGQUIT used with old ++ disposition. Same applies for sigprocmask. */ ++ __sigaction (SIGINT, &intr, NULL); ++ __sigaction (SIGQUIT, &quit, NULL); ++ __sigprocmask (SIG_SETMASK, &omask, NULL); + } + DO_UNLOCK (); + +diff --git a/sysdeps/unix/sysv/linux/ia64/system.c b/sysdeps/unix/sysv/linux/ia64/system.c +deleted file mode 100644 +index d09fefefe64753ab..0000000000000000 +--- a/sysdeps/unix/sysv/linux/ia64/system.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* Copyright (C) 2002-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ +- &pid, NULL, NULL) +- +-#include +diff --git a/sysdeps/unix/sysv/linux/not-errno.h b/sysdeps/unix/sysv/linux/not-errno.h +index 106ba5c72e3d7dda..b2f72cfb3d412c56 100644 +--- a/sysdeps/unix/sysv/linux/not-errno.h ++++ b/sysdeps/unix/sysv/linux/not-errno.h +@@ -16,6 +16,9 @@ + License along with the GNU C Library; if not, see + . */ + ++#include ++#include ++ + /* This function is used on maybe_enable_malloc_check (elf/dl-tunables.c) + and to avoid having to build/use multiple versions if stack protection + in enabled it is defined as inline. */ +@@ -33,3 +36,14 @@ __access_noerrno (const char *pathname, int mode) + return INTERNAL_SYSCALL_ERRNO (res, err); + return 0; + } ++ ++static inline int ++__kill_noerrno (pid_t pid, int sig) ++{ ++ int res; ++ INTERNAL_SYSCALL_DECL (err); ++ res = INTERNAL_SYSCALL_CALL (kill, err, pid, sig); ++ if (INTERNAL_SYSCALL_ERROR_P (res, err)) ++ return INTERNAL_SYSCALL_ERRNO (res, err); ++ return 0; ++} +diff --git a/sysdeps/unix/sysv/linux/s390/system.c b/sysdeps/unix/sysv/linux/s390/system.c +deleted file mode 100644 +index d8ef46133419dd89..0000000000000000 +--- a/sysdeps/unix/sysv/linux/s390/system.c ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* Copyright (C) 2003-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid) +- +-#include "../system.c" +diff --git a/sysdeps/unix/sysv/linux/sparc/system.c b/sysdeps/unix/sysv/linux/sparc/system.c +deleted file mode 100644 +index 1f65c83399f920d6..0000000000000000 +--- a/sysdeps/unix/sysv/linux/sparc/system.c ++++ /dev/null +@@ -1,29 +0,0 @@ +-/* Copyright (C) 2003-2018 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- . */ +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#define FORK() \ +- INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL) +- +-#include "../system.c" +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index 85239cedbf2a5ab5..6a8bd2ed2e1c29b7 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -138,11 +138,11 @@ __spawni_child (void *arguments) + for (int sig = 1; sig < _NSIG; ++sig) + { + if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) +- && sigismember (&attr->__sd, sig)) ++ && __sigismember (&attr->__sd, sig)) + { + sa.sa_handler = SIG_DFL; + } +- else if (sigismember (&hset, sig)) ++ else if (__sigismember (&hset, sig)) + { + if (__is_internal_signal (sig)) + sa.sa_handler = SIG_IGN; +diff --git a/sysdeps/unix/sysv/linux/system.c b/sysdeps/unix/sysv/linux/system.c +deleted file mode 100644 +index 7cc68a1528ee8f99..0000000000000000 +--- a/sysdeps/unix/sysv/linux/system.c ++++ /dev/null +@@ -1,76 +0,0 @@ +-/* Copyright (C) 2002-2018 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 /* For the real memset prototype. */ +-#include +-#include +-#include +-#include +- +-/* We have to and actually can handle cancelable system(). The big +- problem: we have to kill the child process if necessary. To do +- this a cleanup handler has to be registered and is has to be able +- to find the PID of the child. The main problem is to reliable have +- the PID when needed. It is not necessary for the parent thread to +- return. It might still be in the kernel when the cancellation +- request comes. Therefore we have to use the clone() calls ability +- to have the kernel write the PID into the user-level variable. */ +-#ifndef FORK +-# define FORK() \ +- INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid) +-#endif +- +-#ifdef _LIBC_REENTRANT +-static void cancel_handler (void *arg); +- +-# define CLEANUP_HANDLER \ +- __libc_cleanup_region_start (1, cancel_handler, &pid) +- +-# define CLEANUP_RESET \ +- __libc_cleanup_region_end (0) +-#endif +- +- +-/* Linux has waitpid(), so override the generic unix version. */ +-#include +- +- +-#ifdef _LIBC_REENTRANT +-/* The cancellation handler. */ +-static void +-cancel_handler (void *arg) +-{ +- pid_t child = *(pid_t *) arg; +- +- INTERNAL_SYSCALL_DECL (err); +- INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL); +- +- TEMP_FAILURE_RETRY (__waitpid (child, NULL, 0)); +- +- DO_LOCK (); +- +- if (SUB_REF () == 0) +- { +- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); +- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); +- } +- +- DO_UNLOCK (); +-} +-#endif diff --git a/SOURCES/glibc-rh2065588-4.patch b/SOURCES/glibc-rh2065588-4.patch new file mode 100644 index 0000000..33a0cce --- /dev/null +++ b/SOURCES/glibc-rh2065588-4.patch @@ -0,0 +1,194 @@ +commit f09542c584b121da0322fde4b55306d512b85d93 +Author: Adhemerval Zanella +Date: Mon Mar 23 15:23:20 2020 -0300 + + posix: Fix system error return value [BZ #25715] + + It fixes 5fb7fc9635 when posix_spawn fails. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + + Reviewed-by: Carlos O'Donell + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index d14839f3ec3a7bad..b61bd347df7ec46a 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -17,14 +17,128 @@ + . */ + + #include ++#include ++#include ++#include ++#include + ++#include ++#include ++#include ++#include ++ ++static char *tmpdir; ++static long int namemax; ++ ++static void ++do_prepare (int argc, char *argv[]) ++{ ++ tmpdir = support_create_temp_directory ("tst-system-"); ++ /* Include the last '/0'. */ ++ namemax = pathconf (tmpdir, _PC_NAME_MAX) + 1; ++ TEST_VERIFY_EXIT (namemax != -1); ++} ++#define PREPARE do_prepare ++ ++struct args ++{ ++ const char *command; ++ int exit_status; ++ int term_sig; ++ const char *path; ++}; ++ ++static void ++call_system (void *closure) ++{ ++ struct args *args = (struct args *) closure; ++ int ret; ++ ++ if (args->path != NULL) ++ TEST_COMPARE (setenv ("PATH", args->path, 1), 0); ++ ret = system (args->command); ++ if (args->term_sig == 0) ++ { ++ /* Expect regular termination. */ ++ TEST_VERIFY (WIFEXITED (ret) != 0); ++ TEST_COMPARE (WEXITSTATUS (ret), args->exit_status); ++ } ++ else ++ { ++ /* status_or_signal < 0. Expect termination by signal. */ ++ TEST_VERIFY (WIFSIGNALED (ret) != 0); ++ TEST_COMPARE (WTERMSIG (ret), args->term_sig); ++ } ++} + + static int + do_test (void) + { +- return system (":"); +-} ++ TEST_VERIFY (system (NULL) != 0); + ++ { ++ char cmd[namemax]; ++ memset (cmd, 'a', sizeof(cmd)); ++ cmd[sizeof(cmd) - 1] = '\0'; ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ cmd, 127, 0, tmpdir ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); ++ ++ char *returnerr = xasprintf ("%s: 1: %s: not found\n", ++ basename(_PATH_BSHELL), cmd); ++ TEST_COMPARE_STRING (result.err.buffer, returnerr); ++ free (returnerr); ++ } ++ ++ { ++ char cmd[namemax + 1]; ++ memset (cmd, 'a', sizeof(cmd)); ++ cmd[sizeof(cmd) - 1] = '\0'; ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ cmd, 127, 0, tmpdir ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); ++ ++ char *returnerr = xasprintf ("%s: 1: %s: File name too long\n", ++ basename(_PATH_BSHELL), cmd); ++ TEST_COMPARE_STRING (result.err.buffer, returnerr); ++ free (returnerr); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ "kill -USR1 $$", 0, SIGUSR1 ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { "echo ...", 0 }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_stdout); ++ TEST_COMPARE_STRING (result.out.buffer, "...\n"); ++ } ++ ++ { ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { "exit 1", 1 }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ } ++ ++ TEST_COMPARE (system (":"), 0); ++ ++ return 0; ++} + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 8a51a6b9919ec39b..7db09a05c3fbca43 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -97,7 +97,8 @@ cancel_handler (void *arg) + static int + do_system (const char *line) + { +- int status; ++ int status = -1; ++ int ret; + pid_t pid; + struct sigaction sa; + #ifndef _LIBC_REENTRANT +@@ -140,14 +141,14 @@ do_system (const char *line) + __posix_spawnattr_setflags (&spawn_attr, + POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK); + +- status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, +- (char *const[]){ (char*) SHELL_NAME, +- (char*) "-c", +- (char *) line, NULL }, +- __environ); ++ ret = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr, ++ (char *const[]){ (char *) SHELL_NAME, ++ (char *) "-c", ++ (char *) line, NULL }, ++ __environ); + __posix_spawnattr_destroy (&spawn_attr); + +- if (status == 0) ++ if (ret == 0) + { + /* Cancellation results in cleanup handlers running as exceptions in + the block where they were installed, so it is safe to reference +@@ -182,6 +183,9 @@ do_system (const char *line) + } + DO_UNLOCK (); + ++ if (ret != 0) ++ __set_errno (ret); ++ + return status; + } + diff --git a/SOURCES/glibc-rh2065588-5.patch b/SOURCES/glibc-rh2065588-5.patch new file mode 100644 index 0000000..368e759 --- /dev/null +++ b/SOURCES/glibc-rh2065588-5.patch @@ -0,0 +1,64 @@ +commit 7a7226543611897103c7483bec160547294dcf0d +Author: Alexandra Hájková +Date: Sat Dec 26 20:44:34 2020 +0100 + + Add xfchmod to libsupport + +diff --git a/support/Makefile b/support/Makefile +index d2b95539403e416c..4875f52495ef292d 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -91,6 +91,7 @@ libsupport-routines = \ + xdlfcn \ + xdlmopen \ + xdup2 \ ++ xfchmod \ + xfclose \ + xfopen \ + xfork \ +diff --git a/support/xfchmod.c b/support/xfchmod.c +new file mode 100644 +index 0000000000000000..4323b9ca8e078c98 +--- /dev/null ++++ b/support/xfchmod.c +@@ -0,0 +1,28 @@ ++/* fchmod with error checking. ++ 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 ++ ++void ++xfchmod (int fd, mode_t mode) ++{ ++ if (fchmod (fd, mode) != 0) ++ FAIL_EXIT1 ("fchmod (%d, 0%o): %m", fd, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index 74fd2771d12c36fe..ced8cb1dd9ee356c 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -45,6 +45,7 @@ long long xlseek (int fd, long long offset, int whence); + void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); ++void xfchmod (int fd, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/SOURCES/glibc-rh2065588-6.patch b/SOURCES/glibc-rh2065588-6.patch new file mode 100644 index 0000000..16fdb47 --- /dev/null +++ b/SOURCES/glibc-rh2065588-6.patch @@ -0,0 +1,56 @@ +commit 7b9c3260bcca73781dda6bc2ddee84869bedfb8c +Author: Adhemerval Zanella +Date: Mon Dec 14 11:42:33 2020 -0300 + + support: Add xchmod wrapper + + Checked on x86_64-linux-gnu. + +diff --git a/support/xchmod.c b/support/xchmod.c +new file mode 100644 +index 0000000000000000..5e403c7cc2705aef +--- /dev/null ++++ b/support/xchmod.c +@@ -0,0 +1,30 @@ ++/* chmod with error checking. ++ 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 ++ ++void ++xchmod (const char *pathname, mode_t mode) ++{ ++ int r = chmod (pathname, mode); ++ if (r < 0) ++ FAIL_EXIT1 ("chmod (%s, %d): %m", pathname, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index ced8cb1dd9ee356c..e92056c65efe8d6a 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -46,6 +46,7 @@ void xftruncate (int fd, long long length); + void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); + void xfchmod (int fd, mode_t mode); ++void xchmod (const char *pathname, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/SOURCES/glibc-rh2065588-7.patch b/SOURCES/glibc-rh2065588-7.patch new file mode 100644 index 0000000..b16b79e --- /dev/null +++ b/SOURCES/glibc-rh2065588-7.patch @@ -0,0 +1,73 @@ +commit 4eda036f5b897fa8bc20ddd2099b5a6ed4239dc9 +Author: Adhemerval Zanella +Date: Tue Mar 24 15:48:34 2020 -0300 + + stdlib: Move tst-system to tests-container + + Fix some issues with different shell and error messages. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 01194bbf7cc96851..9d0edcf6a7749b28 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -70,7 +70,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + test-canon test-canon2 tst-strtoll tst-environ \ + tst-xpg-basename tst-random tst-random2 tst-bsearch \ + tst-limits tst-rand48 bug-strtod tst-setcontext \ +- tst-setcontext2 test-a64l tst-qsort tst-system testmb2 \ ++ tst-setcontext2 test-a64l tst-qsort testmb2 \ + bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 \ + tst-rand48-2 tst-makecontext tst-strtod5 \ + tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \ +@@ -92,6 +92,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ + tst-tls-atexit tst-tls-atexit-nodelete + tests-static := tst-secure-getenv ++tests-container := tst-system + + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-empty-env +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index b61bd347df7ec46a..194e09828dd5c206 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -88,7 +88,8 @@ do_test (void) + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); + +- char *returnerr = xasprintf ("%s: 1: %s: not found\n", ++ char *returnerr = xasprintf ("%s: execing %s failed: " ++ "No such file or directory", + basename(_PATH_BSHELL), cmd); + TEST_COMPARE_STRING (result.err.buffer, returnerr); + free (returnerr); +@@ -106,7 +107,8 @@ do_test (void) + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr); + +- char *returnerr = xasprintf ("%s: 1: %s: File name too long\n", ++ char *returnerr = xasprintf ("%s: execing %s failed: " ++ "File name too long", + basename(_PATH_BSHELL), cmd); + TEST_COMPARE_STRING (result.err.buffer, returnerr); + free (returnerr); +@@ -116,7 +118,7 @@ do_test (void) + struct support_capture_subprocess result; + result = support_capture_subprocess (call_system, + &(struct args) { +- "kill -USR1 $$", 0, SIGUSR1 ++ "kill $$", 0, SIGTERM + }); + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } +@@ -136,7 +138,7 @@ do_test (void) + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } + +- TEST_COMPARE (system (":"), 0); ++ TEST_COMPARE (system (""), 0); + + return 0; + } diff --git a/SOURCES/glibc-rh2065588-8.patch b/SOURCES/glibc-rh2065588-8.patch new file mode 100644 index 0000000..102b72a --- /dev/null +++ b/SOURCES/glibc-rh2065588-8.patch @@ -0,0 +1,74 @@ +commit 42dda89dcb0407f6799dbfd0b9dab1529666ad51 +Author: Adhemerval Zanella +Date: Fri Dec 11 15:23:05 2020 -0300 + + posix: Fix return value of system if shell can not be executed [BZ #27053] + + POSIX states that system returned code for failure to execute the shell + shall be as if the shell had terminated using _exit(127). This + behaviour was removed with 5fb7fc96350575. + + Checked on x86_64-linux-gnu. + +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index 194e09828dd5c206..8681584f15ef3b47 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + static char *tmpdir; + static long int namemax; +@@ -138,6 +139,22 @@ do_test (void) + support_capture_subprocess_check (&result, "system", 0, sc_allow_none); + } + ++ { ++ struct stat64 st; ++ xstat (_PATH_BSHELL, &st); ++ mode_t mode = st.st_mode; ++ xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH)); ++ ++ struct support_capture_subprocess result; ++ result = support_capture_subprocess (call_system, ++ &(struct args) { ++ "exit 1", 127, 0 ++ }); ++ support_capture_subprocess_check (&result, "system", 0, sc_allow_none); ++ ++ xchmod (_PATH_BSHELL, st.st_mode); ++ } ++ + TEST_COMPARE (system (""), 0); + + return 0; +diff --git a/support/Makefile b/support/Makefile +index 4875f52495ef292d..09b41b0d57e9239a 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -86,6 +86,7 @@ libsupport-routines = \ + xchroot \ + xclone \ + xclose \ ++ xchmod \ + xconnect \ + xcopy_file_range \ + xdlfcn \ +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 7db09a05c3fbca43..047ded4badfddcab 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -171,6 +171,10 @@ do_system (const char *line) + __libc_cleanup_region_end (0); + #endif + } ++ else ++ /* POSIX states that failure to execute the shell should return ++ as if the shell had terminated using _exit(127). */ ++ status = W_EXITCODE (127, 0); + + DO_LOCK (); + if (SUB_REF () == 0) diff --git a/SOURCES/glibc-rh2065588-9.patch b/SOURCES/glibc-rh2065588-9.patch new file mode 100644 index 0000000..6d259d8 --- /dev/null +++ b/SOURCES/glibc-rh2065588-9.patch @@ -0,0 +1,21 @@ +commit 542160f0b6a7c26758c9575a8876f6624a5dd65f +Author: Girish Joshi +Date: Mon Mar 2 15:19:29 2020 -0500 + + Fixed typo in run_command_array() in support/shell-container.c + + https://sourceware.org/bugzilla/show_bug.cgi?id=23991 + +diff --git a/support/shell-container.c b/support/shell-container.c +index 9bd90d3f60529079..e87ac5cf1baa84e5 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -228,7 +228,7 @@ run_command_array (char **argv) + if (new_stderr != 2) + { + dup2 (new_stderr, 2); +- close (new_stdout); ++ close (new_stderr); + } + + if (builtin_func != NULL) diff --git a/SOURCES/glibc-rh2071745.patch b/SOURCES/glibc-rh2071745.patch new file mode 100644 index 0000000..8fbfffb --- /dev/null +++ b/SOURCES/glibc-rh2071745.patch @@ -0,0 +1,23 @@ +commit 62db87ab24f9ca483f97f5e52ea92445f6a63c6f +Author: Adhemerval Zanella +Date: Mon Jan 10 10:17:18 2022 -0300 + + timezone: Fix tst-bz28707 Makefile rule + + The $(testdata)/XT5 rule is ambiguous and it may not be correct + evaluated. + +diff --git a/timezone/Makefile b/timezone/Makefile +index ac7f483c130b5b4a..c4a63daadb8d5dc5 100644 +--- a/timezone/Makefile ++++ b/timezone/Makefile +@@ -123,7 +123,8 @@ $(testdata)/XT%: testdata/XT% + $(make-target-directory) + cp $< $@ + +-$(testdata)/XT%: testdata/gen-XT%.sh ++$(testdata)/XT5: testdata/gen-XT5.sh ++ $(make-target-directory) + $(SHELL) $< > $@.tmp + mv $@.tmp $@ + diff --git a/SOURCES/glibc-rh2072329.patch b/SOURCES/glibc-rh2072329.patch new file mode 100644 index 0000000..e26331e --- /dev/null +++ b/SOURCES/glibc-rh2072329.patch @@ -0,0 +1,86 @@ +commit 33e03f9cd2be4f2cd62f93fda539cc07d9c8130e +Author: Joan Bruguera +Date: Mon Apr 11 19:49:56 2022 +0200 + + misc: Fix rare fortify crash on wchar funcs. [BZ 29030] + + If `__glibc_objsize (__o) == (size_t) -1` (i.e. `__o` is unknown size), fortify + checks should pass, and `__whatever_alias` should be called. + + Previously, `__glibc_objsize (__o) == (size_t) -1` was explicitly checked, but + on commit a643f60c53876b, this was moved into `__glibc_safe_or_unknown_len`. + + A comment says the -1 case should work as: "The -1 check is redundant because + since it implies that __glibc_safe_len_cond is true.". But this fails when: + * `__s > 1` + * `__osz == -1` (i.e. unknown size at compile time) + * `__l` is big enough + * `__l * __s <= __osz` can be folded to a constant + (I only found this to be true for `mbsrtowcs` and other functions in wchar2.h) + + In this case `__l * __s <= __osz` is false, and `__whatever_chk_warn` will be + called by `__glibc_fortify` or `__glibc_fortify_n` and crash the program. + + This commit adds the explicit `__osz == -1` check again. + moc crashes on startup due to this, see: https://bugs.archlinux.org/task/74041 + + Minimal test case (test.c): + #include + + int main (void) + { + const char *hw = "HelloWorld"; + mbsrtowcs (NULL, &hw, (size_t)-1, NULL); + return 0; + } + + Build with: + gcc -O2 -Wp,-D_FORTIFY_SOURCE=2 test.c -o test && ./test + + Output: + *** buffer overflow detected ***: terminated + + Fixes: BZ #29030 + Signed-off-by: Joan Bruguera + Signed-off-by: Siddhesh Poyarekar + +diff --git a/debug/tst-fortify.c b/debug/tst-fortify.c +index 1668294e48b5c63c..701bffd1d664f289 100644 +--- a/debug/tst-fortify.c ++++ b/debug/tst-fortify.c +@@ -1505,6 +1505,11 @@ do_test (void) + CHK_FAIL_END + #endif + ++ /* Bug 29030 regresion check */ ++ cp = "HelloWorld"; ++ if (mbsrtowcs (NULL, &cp, (size_t)-1, &s) != 10) ++ FAIL (); ++ + cp = "A"; + if (mbstowcs (wenough, cp, 10) != 1 + || wcscmp (wenough, L"A") != 0) +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index a17ae0ed87e6163f..404496c7d6da4fb3 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -143,13 +143,13 @@ + || (__builtin_constant_p (__l) && (__l) > 0)) + + /* Length is known to be safe at compile time if the __L * __S <= __OBJSZ +- condition can be folded to a constant and if it is true. The -1 check is +- redundant because since it implies that __glibc_safe_len_cond is true. */ ++ condition can be folded to a constant and if it is true, or unknown (-1) */ + #define __glibc_safe_or_unknown_len(__l, __s, __osz) \ +- (__glibc_unsigned_or_positive (__l) \ +- && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ +- __s, __osz)) \ +- && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), __s, __osz)) ++ ((__osz) == (__SIZE_TYPE__) -1 \ ++ || (__glibc_unsigned_or_positive (__l) \ ++ && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ ++ (__s), (__osz))) \ ++ && __glibc_safe_len_cond ((__SIZE_TYPE__) (__l), (__s), (__osz)))) + + /* Conversely, we know at compile time that the length is unsafe if the + __L * __S <= __OBJSZ condition can be folded to a constant and if it is diff --git a/SOURCES/glibc-rh2077835.patch b/SOURCES/glibc-rh2077835.patch new file mode 100644 index 0000000..7323d49 --- /dev/null +++ b/SOURCES/glibc-rh2077835.patch @@ -0,0 +1,211 @@ +commit 2376944b9e5c0364b9fb473e4d8dabca31b57167 +Author: Stefan Liebler +Date: Wed Apr 13 14:36:09 2022 +0200 + + S390: Add new s390 platform z16. + + The new IBM z16 is added to platform string array. + The macro _DL_PLATFORMS_COUNT is incremented. + + _dl_hwcaps_subdir is extended by "z16" if HWCAP_S390_VXRS_PDE2 + is set. HWCAP_S390_NNPA is not tested in _dl_hwcaps_subdirs_active + as those instructions may be replaced or removed in future. + + tst-glibc-hwcaps.c is extended in order to test z16 via new marker5. + + A fatal glibc error is dumped if glibc was build with architecture + level set for z16, but run on an older machine. (See dl-hwcap-check.h) + +Reworked for RHEL 8.7.0 + +diff -Nrup a/elf/Makefile b/elf/Makefile +--- a/elf/Makefile 2022-05-16 21:48:11.267916411 -0400 ++++ b/elf/Makefile 2022-05-16 21:48:56.106095151 -0400 +@@ -347,7 +347,8 @@ modules-names = testobj1 testobj2 testob + libmarkermod2-1 libmarkermod2-2 \ + libmarkermod3-1 libmarkermod3-2 libmarkermod3-3 \ + libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ +- tst-tls20mod-bad tst-tls21mod \ ++ libmarkermod5-1 libmarkermod5-2 libmarkermod5-3 libmarkermod5-4 \ ++ libmarkermod5-5 tst-tls20mod-bad tst-tls21mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -1782,6 +1783,7 @@ LDFLAGS-libmarkermod1-1.so += -Wl,-sonam + LDFLAGS-libmarkermod2-1.so += -Wl,-soname,libmarkermod2.so + LDFLAGS-libmarkermod3-1.so += -Wl,-soname,libmarkermod3.so + LDFLAGS-libmarkermod4-1.so += -Wl,-soname,libmarkermod4.so ++LDFLAGS-libmarkermod5-1.so += -Wl,-soname,libmarkermod5.so + $(objpfx)libmarkermod%.os : markermodMARKER-VALUE.c + $(compile-command.c) \ + -DMARKER=marker$(firstword $(subst -, ,$*)) \ +@@ -1794,6 +1796,8 @@ $(objpfx)libmarkermod3.so: $(objpfx)libm + cp $< $@ + $(objpfx)libmarkermod4.so: $(objpfx)libmarkermod4-1.so + cp $< $@ ++$(objpfx)libmarkermod5.so: $(objpfx)libmarkermod5-1.so ++ cp $< $@ + + # tst-glibc-hwcaps-prepend checks that --glibc-hwcaps-prepend is + # preferred over auto-detected subdirectories. +diff -Nrup a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +--- a/elf/tst-glibc-hwcaps-cache.script 2022-05-16 21:48:11.053915558 -0400 ++++ b/elf/tst-glibc-hwcaps-cache.script 2022-05-16 21:48:56.107095155 -0400 +@@ -4,6 +4,7 @@ + cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so + cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so + cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so ++cp $B/elf/libmarkermod5-1.so $L/libmarkermod5.so + + mkdirp 0770 $L/glibc-hwcaps/power9 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so +@@ -20,6 +21,11 @@ mkdirp 0770 $L/glibc-hwcaps/z15 + cp $B/elf/libmarkermod4-2.so $L/glibc-hwcaps/z13/libmarkermod4.so + cp $B/elf/libmarkermod4-3.so $L/glibc-hwcaps/z14/libmarkermod4.so + cp $B/elf/libmarkermod4-4.so $L/glibc-hwcaps/z15/libmarkermod4.so ++mkdirp 0770 $L/glibc-hwcaps/z16 ++cp $B/elf/libmarkermod5-2.so $L/glibc-hwcaps/z13/libmarkermod5.so ++cp $B/elf/libmarkermod5-3.so $L/glibc-hwcaps/z14/libmarkermod5.so ++cp $B/elf/libmarkermod5-4.so $L/glibc-hwcaps/z15/libmarkermod5.so ++cp $B/elf/libmarkermod5-5.so $L/glibc-hwcaps/z16/libmarkermod5.so + + mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so +diff -Nrup a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +--- a/sysdeps/s390/dl-procinfo.c 2022-05-16 21:48:11.250916343 -0400 ++++ b/sysdeps/s390/dl-procinfo.c 2022-05-16 21:48:56.107095155 -0400 +@@ -64,11 +64,12 @@ PROCINFO_CLASS const char _dl_s390_cap_f + #if !defined PROCINFO_DECL && defined SHARED + ._dl_s390_platforms + #else +-PROCINFO_CLASS const char _dl_s390_platforms[10][7] ++PROCINFO_CLASS const char _dl_s390_platforms[11][7] + #endif + #ifndef PROCINFO_DECL + = { +- "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15" ++ "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15", ++ "z16" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +diff -Nrup a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +--- a/sysdeps/s390/dl-procinfo.h 2022-05-16 21:48:11.250916343 -0400 ++++ b/sysdeps/s390/dl-procinfo.h 2022-05-16 21:48:56.107095155 -0400 +@@ -23,7 +23,7 @@ + + #define _DL_HWCAP_COUNT 23 + +-#define _DL_PLATFORMS_COUNT 10 ++#define _DL_PLATFORMS_COUNT 11 + + /* The kernel provides up to 32 capability bits with elf_hwcap. */ + #define _DL_FIRST_PLATFORM 32 +diff -Nrup a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +--- a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c 2022-05-16 21:58:02.840301911 -0400 +@@ -19,8 +19,8 @@ + #include + #include + +-const char _dl_hwcaps_subdirs[] = "z15:z14:z13"; +-enum { subdirs_count = 3 }; /* Number of components in _dl_hwcaps_subdirs. */ ++const char _dl_hwcaps_subdirs[] = "z16:z15:z14:z13"; ++enum { subdirs_count = 4 }; /* Number of components in _dl_hwcaps_subdirs. */ + + uint32_t + _dl_hwcaps_subdirs_active (void) +@@ -50,5 +50,12 @@ _dl_hwcaps_subdirs_active (void) + return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); + ++active; + ++ /* z16. ++ Note: We do not list HWCAP_S390_NNPA here as, according to the Principles of ++ Operation, those instructions may be replaced or removed in future. */ ++ if (!(GLRO (dl_hwcap) & HWCAP_S390_VXRS_PDE2)) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ + return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); + } +diff -Nrup a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile +--- a/sysdeps/s390/s390-64/Makefile 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/Makefile 2022-05-16 21:54:08.832355745 -0400 +@@ -7,8 +7,11 @@ CFLAGS-rtld.c += -Wno-uninitialized -Wno + CFLAGS-dl-load.c += -Wno-unused + CFLAGS-dl-reloc.c += -Wno-unused + +-$(objpfx)tst-glibc-hwcaps: $(objpfx)libmarkermod2-1.so \ +- $(objpfx)libmarkermod3-1.so $(objpfx)libmarkermod4-1.so ++$(objpfx)tst-glibc-hwcaps: \ ++ $(objpfx)libmarkermod2-1.so \ ++ $(objpfx)libmarkermod3-1.so \ ++ $(objpfx)libmarkermod4-1.so \ ++ $(objpfx)libmarkermod5-1.so + $(objpfx)tst-glibc-hwcaps.out: \ + $(objpfx)libmarkermod2.so \ + $(objpfx)glibc-hwcaps/z13/libmarkermod2.so \ +@@ -19,6 +22,11 @@ $(objpfx)tst-glibc-hwcaps.out: \ + $(objpfx)glibc-hwcaps/z13/libmarkermod4.so \ + $(objpfx)glibc-hwcaps/z14/libmarkermod4.so \ + $(objpfx)glibc-hwcaps/z15/libmarkermod4.so \ ++ $(objpfx)libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z14/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z15/libmarkermod5.so \ ++ $(objpfx)glibc-hwcaps/z16/libmarkermod5.so + + $(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so + $(make-target-directory) +@@ -38,6 +46,18 @@ $(objpfx)glibc-hwcaps/z14/libmarkermod4. + $(objpfx)glibc-hwcaps/z15/libmarkermod4.so: $(objpfx)libmarkermod4-4.so + $(make-target-directory) + cp $< $@ ++$(objpfx)glibc-hwcaps/z13/libmarkermod5.so: $(objpfx)libmarkermod5-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z14/libmarkermod5.so: $(objpfx)libmarkermod5-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z15/libmarkermod5.so: $(objpfx)libmarkermod5-4.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z16/libmarkermod5.so: $(objpfx)libmarkermod5-5.so ++ $(make-target-directory) ++ cp $< $@ + + ifeq (no,$(build-hardcoded-path-in-tests)) + # This is an ld.so.cache test, and RPATH/RUNPATH in the executable +diff -Nrup a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +--- a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c 2022-05-16 21:48:11.053915558 -0400 ++++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c 2022-05-16 21:48:56.107095155 -0400 +@@ -25,6 +25,7 @@ + extern int marker2 (void); + extern int marker3 (void); + extern int marker4 (void); ++extern int marker5 (void); + + /* Return the arch level, 10 for the baseline libmarkermod*.so's. */ + static int +@@ -63,9 +64,13 @@ compute_level (void) + return 12; + if (strcmp (platform, "z15") == 0) + return 13; ++ if (strcmp (platform, "z16") == 0) ++ return 14; + printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform); + /* Assume that the new platform supports z15. */ + return 13; ++ /* Assume that the new platform supports z16. */ ++ return 14; + } + + static int +@@ -76,6 +81,7 @@ do_test (void) + TEST_COMPARE (marker2 (), MIN (level - 9, 2)); + TEST_COMPARE (marker3 (), MIN (level - 9, 3)); + TEST_COMPARE (marker4 (), MIN (level - 9, 4)); ++ TEST_COMPARE (marker5 (), MIN (level - 9, 5)); + return 0; + } + diff --git a/SOURCES/glibc-rh2080349-1.patch b/SOURCES/glibc-rh2080349-1.patch new file mode 100644 index 0000000..0bc7524 --- /dev/null +++ b/SOURCES/glibc-rh2080349-1.patch @@ -0,0 +1,37 @@ +commit 4a7c342605bc653f72d60c36abe698986fb5cb47 +Author: Joseph Myers +Date: Wed Apr 28 17:19:24 2021 +0000 + + Update syscall lists for Linux 5.12. + + Linux 5.12 has one new syscall, mount_setattr. Update + syscall-names.list and regenerate the arch-syscall.h headers with + build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.12. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index f6cb34089d..8e3cfa0e77 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.11. +-kernel 5.11 ++# The list of system calls is current as of Linux 5.12. ++kernel 5.12 + + FAST_atomic_update + FAST_cmpxchg +@@ -258,6 +258,7 @@ mmap + mmap2 + modify_ldt + mount ++mount_setattr + move_mount + move_pages + mprotect diff --git a/SOURCES/glibc-rh2080349-2.patch b/SOURCES/glibc-rh2080349-2.patch new file mode 100644 index 0000000..6084110 --- /dev/null +++ b/SOURCES/glibc-rh2080349-2.patch @@ -0,0 +1,40 @@ +commit b1b4f7209ecaad4bf9a5d0d2ef1338409d364bac +Author: Joseph Myers +Date: Thu Jul 1 17:37:36 2021 +0000 + + Update syscall lists for Linux 5.13 + + Linux 5.13 has three new syscalls (landlock_create_ruleset, + landlock_add_rule, landlock_restrict_self). Update syscall-names.list + and regenerate the arch-syscall.h headers with build-many-glibcs.py + update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.13. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 8e3cfa0e77..89c5895b9b 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.12. +-kernel 5.12 ++# The list of system calls is current as of Linux 5.13. ++kernel 5.13 + + FAST_atomic_update + FAST_cmpxchg +@@ -224,6 +224,9 @@ kexec_file_load + kexec_load + keyctl + kill ++landlock_add_rule ++landlock_create_ruleset ++landlock_restrict_self + lchown + lchown32 + lgetxattr diff --git a/SOURCES/glibc-rh2080349-3.patch b/SOURCES/glibc-rh2080349-3.patch new file mode 100644 index 0000000..7293e03 --- /dev/null +++ b/SOURCES/glibc-rh2080349-3.patch @@ -0,0 +1,45 @@ +commit 89dc0372a9055e7ef86fe19be6201fa0b16b2f0e +Author: Joseph Myers +Date: Wed Sep 8 12:42:06 2021 +0000 + + Update syscall lists for Linux 5.14 + + Linux 5.14 has two new syscalls, memfd_secret (on some architectures + only) and quotactl_fd. Update syscall-names.list and regenerate the + arch-syscall.h headers with build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.14. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 89c5895b9b..fd98893b0e 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.13. +-kernel 5.13 ++# The list of system calls is current as of Linux 5.14. ++kernel 5.14 + + FAST_atomic_update + FAST_cmpxchg +@@ -247,6 +247,7 @@ madvise + mbind + membarrier + memfd_create ++memfd_secret + memory_ordering + migrate_pages + mincore +@@ -452,6 +453,7 @@ pwritev + pwritev2 + query_module + quotactl ++quotactl_fd + read + readahead + readdir diff --git a/SOURCES/glibc-rh2080349-4.patch b/SOURCES/glibc-rh2080349-4.patch new file mode 100644 index 0000000..205b903 --- /dev/null +++ b/SOURCES/glibc-rh2080349-4.patch @@ -0,0 +1,43 @@ +commit 3387c40a8bbad5faf85b1feb56429cb20feaa640 +Author: Joseph Myers +Date: Wed Nov 10 15:21:19 2021 +0000 + + Update syscall lists for Linux 5.15 + + Linux 5.15 has one new syscall, process_mrelease (and also enables the + clone3 syscall for RV32). It also has a macro __NR_SYSCALL_MASK for + Arm, which is not a syscall but matches the pattern used for syscall + macro names. + + Add __NR_SYSCALL_MASK to the names filtered out in the code dealing + with syscall lists, update syscall-names.list for the new syscall and + regenerate the arch-syscall.h headers with build-many-glibcs.py + update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.15. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index fd98893b0e..1a74d090b7 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.14. +-kernel 5.14 ++# The list of system calls is current as of Linux 5.15. ++kernel 5.15 + + FAST_atomic_update + FAST_cmpxchg +@@ -440,6 +440,7 @@ preadv + preadv2 + prlimit64 + process_madvise ++process_mrelease + process_vm_readv + process_vm_writev + prof diff --git a/SOURCES/glibc-rh2080349-5.patch b/SOURCES/glibc-rh2080349-5.patch new file mode 100644 index 0000000..b042917 --- /dev/null +++ b/SOURCES/glibc-rh2080349-5.patch @@ -0,0 +1,37 @@ +commit 4997a533ae4b51ef66a6b68862b7578a7acb82df +Author: Joseph Myers +Date: Thu Jan 13 22:18:13 2022 +0000 + + Update syscall lists for Linux 5.16 + + Linux 5.16 has one new syscall, futex_waitv. Update + syscall-names.list and regenerate the arch-syscall.h headers with + build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.16. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index c80a9a59cb..6421806110 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.15. +-kernel 5.15 ++# The list of system calls is current as of Linux 5.16. ++kernel 5.16 + + FAST_atomic_update + FAST_cmpxchg +@@ -146,6 +146,7 @@ ftruncate + ftruncate64 + futex + futex_time64 ++futex_waitv + futimesat + get_kernel_syms + get_mempolicy diff --git a/SOURCES/glibc-rh2080349-6.patch b/SOURCES/glibc-rh2080349-6.patch new file mode 100644 index 0000000..333f362 --- /dev/null +++ b/SOURCES/glibc-rh2080349-6.patch @@ -0,0 +1,37 @@ +commit 8ef9196b26793830515402ea95aca2629f7721ec +Author: Joseph Myers +Date: Wed Mar 23 17:11:56 2022 +0000 + + Update syscall lists for Linux 5.17 + + Linux 5.17 has one new syscall, set_mempolicy_home_node. Update + syscall-names.list and regenerate the arch-syscall.h headers with + build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.17. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 6421806110..b8c0b0c586 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.16. +-kernel 5.16 ++# The list of system calls is current as of Linux 5.17. ++kernel 5.17 + + FAST_atomic_update + FAST_cmpxchg +@@ -524,6 +524,7 @@ sendmmsg + sendmsg + sendto + set_mempolicy ++set_mempolicy_home_node + set_robust_list + set_thread_area + set_tid_address diff --git a/SOURCES/glibc-rh2080349-7.patch b/SOURCES/glibc-rh2080349-7.patch new file mode 100644 index 0000000..067f10e --- /dev/null +++ b/SOURCES/glibc-rh2080349-7.patch @@ -0,0 +1,28 @@ +commit 3d9926663cba19f40d26d8a8ab3b2a7cc09ffb13 +Author: Joseph Myers +Date: Wed May 25 14:37:28 2022 +0000 + + Update syscall-names.list for Linux 5.18 + + Linux 5.18 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 5.18. + + Tested with build-many-glibcs.py. + +Modified to only update syscall-names.list to Linux 5.18. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index b8c0b0c586..6c7b2f7011 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.17. +-kernel 5.17 ++# The list of system calls is current as of Linux 5.18. ++kernel 5.18 + + FAST_atomic_update + FAST_cmpxchg diff --git a/SOURCES/glibc-rh2080349-8.patch b/SOURCES/glibc-rh2080349-8.patch new file mode 100644 index 0000000..5e6fa9f --- /dev/null +++ b/SOURCES/glibc-rh2080349-8.patch @@ -0,0 +1,20 @@ +commit 9dde3a24f132090fa8f88d6eaa2bc4c48f2e942f +Author: Stafford Horne +Date: Sat May 23 12:41:31 2020 +0900 + + linux/syscalls: Add or1k_atomic syscall for OpenRISC + + Reviewed-by: Adhemerval Zanella + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 42701ce583..c80a9a59cb 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -304,6 +304,7 @@ open_by_handle_at + open_tree + openat + openat2 ++or1k_atomic + osf_adjtime + osf_afs_syscall + osf_alt_plock diff --git a/SOURCES/glibc-rh2080349-9.patch b/SOURCES/glibc-rh2080349-9.patch new file mode 100644 index 0000000..080811e --- /dev/null +++ b/SOURCES/glibc-rh2080349-9.patch @@ -0,0 +1,10 @@ +diff -Nrup a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +--- a/sysdeps/unix/sysv/linux/syscall-names.list 2022-07-18 10:44:38.791332453 -0400 ++++ b/sysdeps/unix/sysv/linux/syscall-names.list 2022-07-18 11:02:51.054663735 -0400 +@@ -1,5 +1,5 @@ + # List of all known Linux system calls. +-# Copyright (C) 2017-2021 Free Software Foundation, Inc. ++# Copyright (C) 2017-2022 Free Software Foundation, Inc. + # This file is part of the GNU C Library. + # + # The GNU C Library is free software; you can redistribute it and/or diff --git a/SOURCES/glibc-rh2086853.patch b/SOURCES/glibc-rh2086853.patch new file mode 100644 index 0000000..d11e4cb --- /dev/null +++ b/SOURCES/glibc-rh2086853.patch @@ -0,0 +1,30 @@ +commit 61a87530108ec9181e1b18a9b727ec3cc3ba7532 +Author: Siddhesh Poyarekar +Date: Fri May 13 10:01:47 2022 +0530 + + fortify: Ensure that __glibc_fortify condition is a constant [BZ #29141] + + The fix c8ee1c85 introduced a -1 check for object size without also + checking that object size is a constant. Because of this, the tree + optimizer passes in gcc fail to fold away one of the branches in + __glibc_fortify and trips on a spurious Wstringop-overflow. The warning + itself is incorrect and the branch does go away eventually in DCE in the + rtl passes in gcc, but the constant check is a helpful hint to simplify + code early, so add it in. + + Resolves: BZ #29141 + Signed-off-by: Siddhesh Poyarekar + +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index 404496c7d6da4fb3..f3d7efdd2a9320f7 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -145,7 +145,7 @@ + /* Length is known to be safe at compile time if the __L * __S <= __OBJSZ + condition can be folded to a constant and if it is true, or unknown (-1) */ + #define __glibc_safe_or_unknown_len(__l, __s, __osz) \ +- ((__osz) == (__SIZE_TYPE__) -1 \ ++ ((__builtin_constant_p (__osz) && (__osz) == (__SIZE_TYPE__) -1) \ + || (__glibc_unsigned_or_positive (__l) \ + && __builtin_constant_p (__glibc_safe_len_cond ((__SIZE_TYPE__) (__l), \ + (__s), (__osz))) \ diff --git a/SOURCES/glibc-rh2089247-1.patch b/SOURCES/glibc-rh2089247-1.patch new file mode 100644 index 0000000..b3e05ef --- /dev/null +++ b/SOURCES/glibc-rh2089247-1.patch @@ -0,0 +1,47 @@ +commit e1df30fbc2e2167a982c0e77a7ebee28f4dd0800 +Author: Adhemerval Zanella +Date: Thu Jul 25 11:22:17 2019 -0300 + + Get new entropy on each attempt __gen_tempname (BZ #15813) + + This is missing bit for fully fix BZ#15813 (the other two were fixed + by 359653aaacad463). + + Checked on x86_64-linux-gnu. + + [BZ #15813] + sysdeps/posix/tempname.c (__gen_tempname): get entrypy on each + attempt. + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index 3d26f378021680ae..61d7a9f36d37abae 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -186,7 +186,6 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + { + int len; + char *XXXXXX; +- uint64_t value; + unsigned int count; + int fd = -1; + int save_errno = errno; +@@ -218,13 +217,13 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - 6 - suffixlen]; + +- /* Get some more or less random data. */ +- RANDOM_BITS (value); +- value ^= (uint64_t)__getpid () << 32; +- +- for (count = 0; count < attempts; value += 7777, ++count) ++ uint64_t pid = (uint64_t) __getpid () << 32; ++ for (count = 0; count < attempts; ++count) + { +- uint64_t v = value; ++ uint64_t v; ++ /* Get some more or less random data. */ ++ RANDOM_BITS (v); ++ v ^= pid; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; diff --git a/SOURCES/glibc-rh2089247-2.patch b/SOURCES/glibc-rh2089247-2.patch new file mode 100644 index 0000000..84c6ac2 --- /dev/null +++ b/SOURCES/glibc-rh2089247-2.patch @@ -0,0 +1,87 @@ +commit 8eaf34eda256ba3647ed6e7ed5c7c9aa19955d17 +Author: Samuel Thibault +Date: Fri Dec 13 10:10:59 2019 +0100 + + hurd: Fix local PLT + + * include/sys/random.h (__getrandom): Add hidden prototype. + * stdlib/getrandom.c (getrandom): Rename to hidden definition __getrandom. + Add weak alias. + * sysdeps/mach/hurd/getrandom.c (getrandom): Likewise. + * sysdeps/unix/sysv/linux/getrandom.c (getrandom): Likewise. + * sysdeps/mach/hurd/getentropy.c (getentropy): Use __getrandom instead of + getrandom. + +Conflicts: + include/sys/random.h + (Missing backport of include/ consistency patch, + commit ebd32784ce2029d0461a90a79bc4e37f8d051765 upstream.) + sysdeps/mach/hurd/getentropy.c + (Hurd change has been dropped.) + sysdeps/unix/sysv/linux/dl-write.c + (Mismerge of sysdeps/mach/hurd/getrandom.c.) + +diff --git a/include/sys/random.h b/include/sys/random.h +new file mode 100644 +index 0000000000000000..6aa313d35dbdce8a +--- /dev/null ++++ b/include/sys/random.h +@@ -0,0 +1,11 @@ ++#ifndef _SYS_RANDOM_H ++#include ++ ++# ifndef _ISOMAC ++ ++extern ssize_t __getrandom (void *__buffer, size_t __length, ++ unsigned int __flags) __wur; ++libc_hidden_proto (__getrandom) ++ ++# endif /* !_ISOMAC */ ++#endif +diff --git a/stdlib/getrandom.c b/stdlib/getrandom.c +index 45234bea17c5c86c..f8056688e40a0215 100644 +--- a/stdlib/getrandom.c ++++ b/stdlib/getrandom.c +@@ -22,10 +22,12 @@ + /* Write up to LENGTH bytes of randomness starting at BUFFER. + Return the number of bytes written, or -1 on error. */ + ssize_t +-getrandom (void *buffer, size_t length, unsigned int flags) ++__getrandom (void *buffer, size_t length, unsigned int flags) + { + __set_errno (ENOSYS); + return -1; + } +- + stub_warning (getrandom) ++ ++libc_hidden_def (__getrandom) ++weak_alias (__getrandom, getrandom) +diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c +index 435b037399665654..e34d7fdcd89d9b06 100644 +--- a/sysdeps/unix/sysv/linux/getrandom.c ++++ b/sysdeps/unix/sysv/linux/getrandom.c +@@ -25,7 +25,7 @@ + /* Write up to LENGTH bytes of randomness starting at BUFFER. + Return the number of bytes written, or -1 on error. */ + ssize_t +-getrandom (void *buffer, size_t length, unsigned int flags) ++__getrandom (void *buffer, size_t length, unsigned int flags) + { + return SYSCALL_CANCEL (getrandom, buffer, length, flags); + } +@@ -33,7 +33,7 @@ getrandom (void *buffer, size_t length, unsigned int flags) + /* Always provide a definition, even if the kernel headers lack the + system call number. */ + ssize_t +-getrandom (void *buffer, size_t length, unsigned int flags) ++__getrandom (void *buffer, size_t length, unsigned int flags) + { + /* Ideally, we would add a cancellation point here, but we currently + cannot do so inside libc. */ +@@ -41,3 +41,5 @@ getrandom (void *buffer, size_t length, unsigned int flags) + return -1; + } + #endif ++libc_hidden_def (__getrandom) ++weak_alias (__getrandom, getrandom) diff --git a/SOURCES/glibc-rh2089247-3.patch b/SOURCES/glibc-rh2089247-3.patch new file mode 100644 index 0000000..b7f72e6 --- /dev/null +++ b/SOURCES/glibc-rh2089247-3.patch @@ -0,0 +1,67 @@ +Partial backport of: + +commit 04986243d1af37ac0177ed2f9db0a066ebd2b212 +Author: Adhemerval Zanella +Date: Wed Jul 15 19:35:58 2020 +0000 + + Remove internal usage of extensible stat functions + + It replaces the internal usage of __{f,l}xstat{at}{64} with the + __{f,l}stat{at}{64}. It should not change the generate code since + sys/stat.h explicit defines redirections to internal calls back to + xstat* symbols. + + Checked with a build for all affected ABIs. I also check on + x86_64-linux-gnu and i686-linux-gnu. + + Reviewed-by: Lukasz Majewski + +Only the changes to include/sys/stat.h and sysdeps/posix/tempname.c +are included here. + +diff --git a/include/sys/stat.h b/include/sys/stat.h +index b82d4527801d4797..c5b1938b87c9c5c3 100644 +--- a/include/sys/stat.h ++++ b/include/sys/stat.h +@@ -52,6 +52,7 @@ extern __typeof (__fxstatat64) __fxstatat64 attribute_hidden; + #define lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) + #define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) + #define stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) ++#define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) + #define fstat64(fd, buf) __fxstat64 (_STAT_VER, fd, buf) + #define __fstat64(fd, buf) __fxstat64 (_STAT_VER, fd, buf) + #define fstat(fd, buf) __fxstat (_STAT_VER, fd, buf) +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index 61d7a9f36d37abae..a7b404cf4410cb00 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -66,7 +66,6 @@ + # define __gettimeofday gettimeofday + # define __mkdir mkdir + # define __open open +-# define __lxstat64(version, file, buf) lstat (file, buf) + # define __secure_getenv secure_getenv + #endif + +@@ -97,7 +96,7 @@ static int + direxists (const char *dir) + { + struct_stat64 buf; +- return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); ++ return __stat64 (dir, &buf) == 0 && S_ISDIR (buf.st_mode); + } + + /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is +@@ -252,10 +251,10 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + + case __GT_NOCREATE: + /* This case is backward from the other three. __gen_tempname +- succeeds if __xstat fails because the name does not exist. ++ succeeds if lstat fails because the name does not exist. + Note the continue to bypass the common logic at the bottom + of the loop. */ +- if (__lxstat64 (_STAT_VER, tmpl, &st) < 0) ++ if (__lstat64 (tmpl, &st) < 0) + { + if (errno == ENOENT) + { diff --git a/SOURCES/glibc-rh2089247-4.patch b/SOURCES/glibc-rh2089247-4.patch new file mode 100644 index 0000000..878739a --- /dev/null +++ b/SOURCES/glibc-rh2089247-4.patch @@ -0,0 +1,440 @@ +commit 4dddd7e9cbecad4aa03ee5a9b9edb596e3d4e909 +Author: Adhemerval Zanella +Date: Tue Sep 29 08:56:07 2020 -0300 + + posix: Sync tempname with gnulib [BZ #26648] + + It syncs with gnulib commit b1268f22f443e8e4b9e. The try_tempname_len + now uses getrandom on each iteration to get entropy and only uses the + clock plus ASLR as source of entropy if getrandom fails. + + Checked on x86_64-linux-gnu and i686-linux-gnu. + +Conflicts: + sysdeps/posix/tempname.c + (Missing tree-wide __gettimeofday to clock_gettime change, + commit 4a39c34c4f85de57fb4e648cfa1e774437d69680 upstream. + File was rebased to the upstream version.) + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index a7b404cf4410cb00..f199b25a7a227751 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -1,4 +1,4 @@ +-/* Copyright (C) 1991-2018 Free Software Foundation, Inc. ++/* Copyright (C) 1991-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 +@@ -13,10 +13,10 @@ + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see +- . */ ++ . */ + + #if !_LIBC +-# include ++# include + # include "tempname.h" + #endif + +@@ -24,9 +24,6 @@ + #include + + #include +-#ifndef __set_errno +-# define __set_errno(Val) errno = (Val) +-#endif + + #include + #ifndef P_tmpdir +@@ -36,12 +33,12 @@ + # define TMP_MAX 238328 + #endif + #ifndef __GT_FILE +-# define __GT_FILE 0 +-# define __GT_DIR 1 +-# define __GT_NOCREATE 2 ++# define __GT_FILE 0 ++# define __GT_DIR 1 ++# define __GT_NOCREATE 2 + #endif +-#if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR \ +- || GT_NOCREATE != __GT_NOCREATE) ++#if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR \ ++ || GT_NOCREATE != __GT_NOCREATE) + # error report this to bug-gnulib@gnu.org + #endif + +@@ -50,11 +47,11 @@ + #include + + #include +-#include ++#include + #include +-#include +- ++#include + #include ++#include + + #if _LIBC + # define struct_stat64 struct stat64 +@@ -62,33 +59,38 @@ + #else + # define struct_stat64 struct stat + # define __gen_tempname gen_tempname +-# define __getpid getpid +-# define __gettimeofday gettimeofday + # define __mkdir mkdir + # define __open open +-# define __secure_getenv secure_getenv ++# define __lstat64(file, buf) lstat (file, buf) ++# define __stat64(file, buf) stat (file, buf) ++# define __getrandom getrandom ++# define __clock_gettime64 clock_gettime ++# define __timespec64 timespec + #endif + +-#ifdef _LIBC +-# include +-# define RANDOM_BITS(Var) ((Var) = random_bits ()) +-# else +-# define RANDOM_BITS(Var) \ +- { \ +- struct timeval tv; \ +- __gettimeofday (&tv, NULL); \ +- (Var) = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ +- } +-#endif ++/* Use getrandom if it works, falling back on a 64-bit linear ++ congruential generator that starts with Var's value ++ mixed in with a clock's low-order bits if available. */ ++typedef uint_fast64_t random_value; ++#define RANDOM_VALUE_MAX UINT_FAST64_MAX ++#define BASE_62_DIGITS 10 /* 62**10 < UINT_FAST64_MAX */ ++#define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62) + +-/* Use the widest available unsigned type if uint64_t is not +- available. The algorithm below extracts a number less than 62**6 +- (approximately 2**35.725) from uint64_t, so ancient hosts where +- uintmax_t is only 32 bits lose about 3.725 bits of randomness, +- which is better than not having mkstemp at all. */ +-#if !defined UINT64_MAX && !defined uint64_t +-# define uint64_t uintmax_t ++static random_value ++random_bits (random_value var) ++{ ++ random_value r; ++ /* Without GRND_NONBLOCK it can be blocked for minutes on some systems. */ ++ if (__getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r) ++ return r; ++#if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME) ++ /* Add entropy if getrandom did not work. */ ++ struct __timespec64 tv; ++ __clock_gettime64 (CLOCK_MONOTONIC, &tv); ++ var ^= tv.tv_nsec; + #endif ++ return 2862933555777941757 * var + 3037000493; ++} + + #if _LIBC + /* Return nonzero if DIR is an existent directory. */ +@@ -107,7 +109,7 @@ direxists (const char *dir) + enough space in TMPL. */ + int + __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, +- int try_tmpdir) ++ int try_tmpdir) + { + const char *d; + size_t dlen, plen; +@@ -121,35 +123,35 @@ __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, + { + plen = strlen (pfx); + if (plen > 5) +- plen = 5; ++ plen = 5; + } + + if (try_tmpdir) + { + d = __secure_getenv ("TMPDIR"); + if (d != NULL && direxists (d)) +- dir = d; ++ dir = d; + else if (dir != NULL && direxists (dir)) +- /* nothing */ ; ++ /* nothing */ ; + else +- dir = NULL; ++ dir = NULL; + } + if (dir == NULL) + { + if (direxists (P_tmpdir)) +- dir = P_tmpdir; ++ dir = P_tmpdir; + else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) +- dir = "/tmp"; ++ dir = "/tmp"; + else +- { +- __set_errno (ENOENT); +- return -1; +- } ++ { ++ __set_errno (ENOENT); ++ return -1; ++ } + } + + dlen = strlen (dir); + while (dlen > 1 && dir[dlen - 1] == '/') +- dlen--; /* remove trailing slashes */ ++ dlen--; /* remove trailing slashes */ + + /* check we have room for "${dir}/${pfx}XXXXXX\0" */ + if (tmpl_len < dlen + 1 + plen + 6 + 1) +@@ -163,39 +165,91 @@ __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, + } + #endif /* _LIBC */ + ++#if _LIBC ++static int try_tempname_len (char *, int, void *, int (*) (char *, void *), ++ size_t); ++#endif ++ ++static int ++try_file (char *tmpl, void *flags) ++{ ++ int *openflags = flags; ++ return __open (tmpl, ++ (*openflags & ~O_ACCMODE) ++ | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); ++} ++ ++static int ++try_dir (char *tmpl, void *flags _GL_UNUSED) ++{ ++ return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); ++} ++ ++static int ++try_nocreate (char *tmpl, void *flags _GL_UNUSED) ++{ ++ struct_stat64 st; ++ ++ if (__lstat64 (tmpl, &st) == 0 || errno == EOVERFLOW) ++ __set_errno (EEXIST); ++ return errno == ENOENT ? 0 : -1; ++} ++ + /* These are the characters used in temporary file names. */ + static const char letters[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + /* Generate a temporary file name based on TMPL. TMPL must match the +- rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix). ++ rules for mk[s]temp (i.e., end in at least X_SUFFIX_LEN "X"s, ++ possibly with a suffix). + The name constructed does not exist at the time of the call to +- __gen_tempname. TMPL is overwritten with the result. ++ this function. TMPL is overwritten with the result. + + KIND may be one of: +- __GT_NOCREATE: simply verify that the name does not exist +- at the time of the call. +- __GT_FILE: create the file using open(O_CREAT|O_EXCL) +- and return a read-write fd. The file is mode 0600. +- __GT_DIR: create a directory, which will be mode 0700. ++ __GT_NOCREATE: simply verify that the name does not exist ++ at the time of the call. ++ __GT_FILE: create the file using open(O_CREAT|O_EXCL) ++ and return a read-write fd. The file is mode 0600. ++ __GT_DIR: create a directory, which will be mode 0700. + + We use a clever algorithm to get hard-to-predict names. */ ++#ifdef _LIBC ++static ++#endif + int +-__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) ++gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind, ++ size_t x_suffix_len) + { +- int len; ++ static int (*const tryfunc[]) (char *, void *) = ++ { ++ [__GT_FILE] = try_file, ++ [__GT_DIR] = try_dir, ++ [__GT_NOCREATE] = try_nocreate ++ }; ++ return try_tempname_len (tmpl, suffixlen, &flags, tryfunc[kind], ++ x_suffix_len); ++} ++ ++#ifdef _LIBC ++static ++#endif ++int ++try_tempname_len (char *tmpl, int suffixlen, void *args, ++ int (*tryfunc) (char *, void *), size_t x_suffix_len) ++{ ++ size_t len; + char *XXXXXX; + unsigned int count; + int fd = -1; + int save_errno = errno; +- struct_stat64 st; + + /* A lower bound on the number of temporary files to attempt to + generate. The maximum total number of temporary file names that + can exist for a given template is 62**6. It should never be + necessary to try all of these combinations. Instead if a reasonable + number of names is tried (we define reasonable as 62**3) fail to +- give the system administrator the chance to remove the problems. */ ++ give the system administrator the chance to remove the problems. ++ This value requires that X_SUFFIX_LEN be at least 3. */ + #define ATTEMPTS_MIN (62 * 62 * 62) + + /* The number of times to attempt to generate a temporary file. To +@@ -206,82 +260,75 @@ __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) + unsigned int attempts = ATTEMPTS_MIN; + #endif + ++ /* A random variable. The initial value is used only the for fallback path ++ on 'random_bits' on 'getrandom' failure. Its initial value tries to use ++ some entropy from the ASLR and ignore possible bits from the stack ++ alignment. */ ++ random_value v = ((uintptr_t) &v) / alignof (max_align_t); ++ ++ /* How many random base-62 digits can currently be extracted from V. */ ++ int vdigits = 0; ++ ++ /* Least unfair value for V. If V is less than this, V can generate ++ BASE_62_DIGITS digits fairly. Otherwise it might be biased. */ ++ random_value const unfair_min ++ = RANDOM_VALUE_MAX - RANDOM_VALUE_MAX % BASE_62_POWER; ++ + len = strlen (tmpl); +- if (len < 6 + suffixlen || memcmp (&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) ++ if (len < x_suffix_len + suffixlen ++ || strspn (&tmpl[len - x_suffix_len - suffixlen], "X") < x_suffix_len) + { + __set_errno (EINVAL); + return -1; + } + + /* This is where the Xs start. */ +- XXXXXX = &tmpl[len - 6 - suffixlen]; ++ XXXXXX = &tmpl[len - x_suffix_len - suffixlen]; + +- uint64_t pid = (uint64_t) __getpid () << 32; + for (count = 0; count < attempts; ++count) + { +- uint64_t v; +- /* Get some more or less random data. */ +- RANDOM_BITS (v); +- v ^= pid; +- +- /* Fill in the random bits. */ +- XXXXXX[0] = letters[v % 62]; +- v /= 62; +- XXXXXX[1] = letters[v % 62]; +- v /= 62; +- XXXXXX[2] = letters[v % 62]; +- v /= 62; +- XXXXXX[3] = letters[v % 62]; +- v /= 62; +- XXXXXX[4] = letters[v % 62]; +- v /= 62; +- XXXXXX[5] = letters[v % 62]; +- +- switch (kind) +- { +- case __GT_FILE: +- fd = __open (tmpl, +- (flags & ~O_ACCMODE) +- | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); +- break; +- +- case __GT_DIR: +- fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); +- break; +- +- case __GT_NOCREATE: +- /* This case is backward from the other three. __gen_tempname +- succeeds if lstat fails because the name does not exist. +- Note the continue to bypass the common logic at the bottom +- of the loop. */ +- if (__lstat64 (tmpl, &st) < 0) +- { +- if (errno == ENOENT) +- { +- __set_errno (save_errno); +- return 0; +- } +- else +- /* Give up now. */ +- return -1; +- } +- continue; +- +- default: +- assert (! "invalid KIND in __gen_tempname"); +- abort (); +- } +- ++ for (size_t i = 0; i < x_suffix_len; i++) ++ { ++ if (vdigits == 0) ++ { ++ do ++ v = random_bits (v); ++ while (unfair_min <= v); ++ ++ vdigits = BASE_62_DIGITS; ++ } ++ ++ XXXXXX[i] = letters[v % 62]; ++ v /= 62; ++ vdigits--; ++ } ++ ++ fd = tryfunc (tmpl, args); + if (fd >= 0) +- { +- __set_errno (save_errno); +- return fd; +- } ++ { ++ __set_errno (save_errno); ++ return fd; ++ } + else if (errno != EEXIST) +- return -1; ++ return -1; + } + + /* We got out of the loop because we ran out of combinations to try. */ + __set_errno (EEXIST); + return -1; + } ++ ++int ++__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) ++{ ++ return gen_tempname_len (tmpl, suffixlen, flags, kind, 6); ++} ++ ++#if !_LIBC ++int ++try_tempname (char *tmpl, int suffixlen, void *args, ++ int (*tryfunc) (char *, void *)) ++{ ++ return try_tempname_len (tmpl, suffixlen, args, tryfunc, 6); ++} ++#endif diff --git a/SOURCES/glibc-rh2089247-5.patch b/SOURCES/glibc-rh2089247-5.patch new file mode 100644 index 0000000..ba26b89 --- /dev/null +++ b/SOURCES/glibc-rh2089247-5.patch @@ -0,0 +1,17 @@ +Downstream-only patch to use non-time64 identifiers in +sysdeps/posix/tempname.c. Upstream has switched to the time64 +symbols. + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index f199b25a7a227751..fcab9b26364021e4 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -56,6 +56,8 @@ + #if _LIBC + # define struct_stat64 struct stat64 + # define __secure_getenv __libc_secure_getenv ++# define __clock_gettime64 __clock_gettime ++# define __timespec64 timespec + #else + # define struct_stat64 struct stat + # define __gen_tempname gen_tempname diff --git a/SOURCES/glibc-rh2089247-6.patch b/SOURCES/glibc-rh2089247-6.patch new file mode 100644 index 0000000..713b457 --- /dev/null +++ b/SOURCES/glibc-rh2089247-6.patch @@ -0,0 +1,66 @@ +commit f430293d842031f2afc3013f156e1018065e480e +Author: Adhemerval Zanella +Date: Tue Jan 12 09:17:09 2021 -0300 + + posix: consume less entropy on tempname + + The first getrandom is used only for __GT_NOCREATE, which is inherently + insecure and can use the entropy as a small improvement. On the + second and later attempts it might help against DoS attacks. + + It sync with gnulib commit 854fbb81d91f7a0f2b463e7ace2499dee2f380f2. + + Checked on x86_64-linux-gnu. + +diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c +index fcab9b26364021e4..3435c4bf75a01f42 100644 +--- a/sysdeps/posix/tempname.c ++++ b/sysdeps/posix/tempname.c +@@ -22,6 +22,7 @@ + + #include + #include ++#include + + #include + +@@ -79,11 +80,11 @@ typedef uint_fast64_t random_value; + #define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62) + + static random_value +-random_bits (random_value var) ++random_bits (random_value var, bool use_getrandom) + { + random_value r; + /* Without GRND_NONBLOCK it can be blocked for minutes on some systems. */ +- if (__getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r) ++ if (use_getrandom && __getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r) + return r; + #if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME) + /* Add entropy if getrandom did not work. */ +@@ -271,6 +272,13 @@ try_tempname_len (char *tmpl, int suffixlen, void *args, + /* How many random base-62 digits can currently be extracted from V. */ + int vdigits = 0; + ++ /* Whether to consume entropy when acquiring random bits. On the ++ first try it's worth the entropy cost with __GT_NOCREATE, which ++ is inherently insecure and can use the entropy to make it a bit ++ less secure. On the (rare) second and later attempts it might ++ help against DoS attacks. */ ++ bool use_getrandom = tryfunc == try_nocreate; ++ + /* Least unfair value for V. If V is less than this, V can generate + BASE_62_DIGITS digits fairly. Otherwise it might be biased. */ + random_value const unfair_min +@@ -294,7 +302,10 @@ try_tempname_len (char *tmpl, int suffixlen, void *args, + if (vdigits == 0) + { + do +- v = random_bits (v); ++ { ++ v = random_bits (v, use_getrandom); ++ use_getrandom = true; ++ } + while (unfair_min <= v); + + vdigits = BASE_62_DIGITS; diff --git a/SOURCES/glibc-rh2091553.patch b/SOURCES/glibc-rh2091553.patch new file mode 100644 index 0000000..376eb48 --- /dev/null +++ b/SOURCES/glibc-rh2091553.patch @@ -0,0 +1,41 @@ +From 82c7441f04e3c2a653ee29672731e040a1799c6b Mon Sep 17 00:00:00 2001 +From: Matheus Castanho +Date: Tue, 7 Jun 2022 10:27:26 -0300 +Subject: powerpc: Fix VSX register number on __strncpy_power9 [BZ #29197] + +__strncpy_power9 initializes VR 18 with zeroes to be used throughout the +code, including when zero-padding the destination string. However, the +v18 reference was mistakenly being used for stxv and stxvl, which take a +VSX vector as operand. The code ended up using the uninitialized VSR 18 +register by mistake. + +Both occurrences have been changed to use the proper VSX number for VR 18 +(i.e. VSR 50). + +Tested on powerpc, powerpc64 and powerpc64le. + +Signed-off-by: Kewen Lin +(cherry picked from commit 0218463dd8265ed937622f88ac68c7d984fe0cfc) + +diff --git a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S +index 291941c1e5..5421525ace 100644 +--- a/sysdeps/powerpc/powerpc64/le/power9/strncpy.S ++++ b/sysdeps/powerpc/powerpc64/le/power9/strncpy.S +@@ -352,7 +352,7 @@ L(zero_padding_loop): + cmpldi cr6,r5,16 /* Check if length was reached. */ + ble cr6,L(zero_padding_end) + +- stxv v18,0(r11) ++ stxv 32+v18,0(r11) + addi r11,r11,16 + addi r5,r5,-16 + +@@ -360,7 +360,7 @@ L(zero_padding_loop): + + L(zero_padding_end): + sldi r10,r5,56 /* stxvl wants size in top 8 bits */ +- stxvl v18,r11,r10 /* Partial store */ ++ stxvl 32+v18,r11,r10 /* Partial store */ + blr + + .align 4 diff --git a/SOURCES/glibc-rh2096189-1.patch b/SOURCES/glibc-rh2096189-1.patch new file mode 100644 index 0000000..33cc310 --- /dev/null +++ b/SOURCES/glibc-rh2096189-1.patch @@ -0,0 +1,67 @@ +commit 62a321b12d0e397af88fa422db65079332f971dc +Author: Florian Weimer +Date: Fri Jun 24 18:16:41 2022 +0200 + + support: Change non-address output format of support_format_dns_packet + + It makes sense to include the owner name (LHS) and record type in the + output, so that they can be checked for correctness. + + Reviewed-by: Carlos O'Donell + +diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c +index 1170eafb0f008fee..ef862bc4c8d14af0 100644 +--- a/support/support_format_dns_packet.c ++++ b/support/support_format_dns_packet.c +@@ -101,6 +101,17 @@ extract_name (struct in_buffer full, struct in_buffer *in, struct dname *value) + return true; + } + ++static void ++extract_name_data (struct in_buffer full, struct in_buffer *rdata, ++ const struct dname *owner, const char *typename, FILE *out) ++{ ++ struct dname name; ++ if (extract_name (full, rdata, &name)) ++ fprintf (out, "data: %s %s %s\n", owner->name, typename, name.name); ++ else ++ fprintf (out, "error: malformed CNAME/PTR record\n"); ++} ++ + char * + support_format_dns_packet (const unsigned char *buffer, size_t length) + { +@@ -206,14 +217,11 @@ support_format_dns_packet (const unsigned char *buffer, size_t length) + } + break; + case T_CNAME: ++ extract_name_data (full, &rdata, &rname, "CNAME", mem.out); ++ break; + case T_PTR: +- { +- struct dname name; +- if (extract_name (full, &rdata, &name)) +- fprintf (mem.out, "name: %s\n", name.name); +- else +- fprintf (mem.out, "error: malformed CNAME/PTR record\n"); +- } ++ extract_name_data (full, &rdata, &rname, "PTR", mem.out); ++ break; + } + } + +diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c +index b1135eebc6c02d55..35f475fe86177772 100644 +--- a/support/tst-support_format_dns_packet.c ++++ b/support/tst-support_format_dns_packet.c +@@ -85,8 +85,8 @@ test_multiple_cnames (void) + "\xc0\x00\x02\x01"; + check_packet (packet, sizeof (packet) - 1, __func__, + "name: www.example\n" +- "name: www1.example\n" +- "name: www2.example\n" ++ "data: www.example CNAME www1.example\n" ++ "data: www1.example CNAME www2.example\n" + "address: 192.0.2.1\n"); + } + diff --git a/SOURCES/glibc-rh2096189-2.patch b/SOURCES/glibc-rh2096189-2.patch new file mode 100644 index 0000000..201f089 --- /dev/null +++ b/SOURCES/glibc-rh2096189-2.patch @@ -0,0 +1,957 @@ +commit f282cdbe7f436c75864e5640a409a10485e9abb2 +Author: Florian Weimer +Date: Fri Jun 24 18:16:41 2022 +0200 + + resolv: Implement no-aaaa stub resolver option + + Reviewed-by: Carlos O'Donell + +Conflicts: + resolv/Makefile + (missing partial libresolv integration downstream) + resolv/res-noaaaa.c + (call ns_name_skip instead of __ns_name_skip (not available + downstream) and ns_name_unpack instead of __ns_name_unpack + (avoid PLT)) + resolv/res_debug.c + resolv/res_init.c + resolv/resolv.h + resolv/tst-resolv-res_init-skeleton.c + (missing trust-ad support downstream) + +diff --git a/resolv/Makefile b/resolv/Makefile +index cee5225f8933f245..ab8ad49b5318ad41 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -57,6 +57,7 @@ tests += \ + tst-resolv-binary \ + tst-resolv-edns \ + tst-resolv-network \ ++ tst-resolv-noaaaa \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ +@@ -110,7 +111,7 @@ libresolv-routines := res_comp res_debug \ + res_data res_mkquery res_query res_send \ + inet_net_ntop inet_net_pton inet_neta base64 \ + ns_parse ns_name ns_netint ns_ttl ns_print \ +- ns_samedomain ns_date res_enable_icmp \ ++ ns_samedomain ns_date res_enable_icmp res-noaaaa \ + compat-hooks compat-gethnamaddr + + libanl-routines := gai_cancel gai_error gai_misc gai_notify gai_suspend \ +@@ -200,6 +201,7 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \ + $(shared-thread-library) ++$(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 99c3b61e1cee4d42..ff0a0b6f7f1f4703 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -123,6 +123,14 @@ static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); ++static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1, ++ int anslen1, ++ const char *qname, ++ struct gaih_addrtuple **pat, ++ char *buffer, size_t buflen, ++ int *errnop, int *h_errnop, ++ int32_t *ttlp); ++ + + static enum nss_status gethostbyname3_context (struct resolv_context *ctx, + const char *name, int af, +@@ -367,17 +375,31 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + int resplen2 = 0; + int ans2p_malloced = 0; + ++ + int olderr = errno; +- int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, ++ int n; ++ ++ if ((ctx->resp->options & RES_NOAAAA) == 0) ++ { ++ n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, + host_buffer.buf->buf, 2048, &host_buffer.ptr, + &ans2p, &nans2p, &resplen2, &ans2p_malloced); +- if (n >= 0) +- { +- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, +- resplen2, name, pat, buffer, buflen, +- errnop, herrnop, ttlp); ++ if (n >= 0) ++ status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, ++ resplen2, name, pat, buffer, buflen, ++ errnop, herrnop, ttlp); + } + else ++ { ++ n = __res_context_search (ctx, name, C_IN, T_A, ++ host_buffer.buf->buf, 2048, NULL, ++ NULL, NULL, NULL, NULL); ++ if (n >= 0) ++ status = gaih_getanswer_noaaaa (host_buffer.buf, n, ++ name, pat, buffer, buflen, ++ errnop, herrnop, ttlp); ++ } ++ if (n < 0) + { + switch (errno) + { +@@ -1386,3 +1408,21 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + + return status; + } ++ ++/* Variant of gaih_getanswer without a second (AAAA) response. */ ++static enum nss_status ++gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname, ++ struct gaih_addrtuple **pat, ++ char *buffer, size_t buflen, ++ int *errnop, int *h_errnop, int32_t *ttlp) ++{ ++ int first = 1; ++ ++ enum nss_status status = NSS_STATUS_NOTFOUND; ++ if (anslen1 > 0) ++ status = gaih_getanswer_slice (answer1, anslen1, qname, ++ &pat, &buffer, &buflen, ++ errnop, h_errnop, ttlp, ++ &first); ++ return status; ++} +diff --git a/resolv/res-noaaaa.c b/resolv/res-noaaaa.c +new file mode 100644 +index 0000000000000000..e2a13cf38a74c160 +--- /dev/null ++++ b/resolv/res-noaaaa.c +@@ -0,0 +1,143 @@ ++/* Implement suppression of AAAA queries. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Returns true if the question type at P matches EXPECTED, and the ++ class is IN. */ ++static bool ++qtype_matches (const unsigned char *p, int expected) ++{ ++ /* This assumes that T_A/C_IN constants are less than 256, which ++ they are. */ ++ return p[0] == 0 && p[1] == expected && p[2] == 0 && p[3] == C_IN; ++} ++ ++/* Handle RES_NOAAAA translation of AAAA queries. To produce a Name ++ Error (NXDOMAIN) repsonse for domain names that do not exist, it is ++ still necessary to send a query. Using question type A is a ++ conservative choice. In the returned answer, it is necessary to ++ switch back the question type to AAAA. */ ++bool ++__res_handle_no_aaaa (struct resolv_context *ctx, ++ const unsigned char *buf, int buflen, ++ unsigned char *ans, int anssiz, int *result) ++{ ++ /* AAAA mode is not active, or the query looks invalid (will not be ++ able to be parsed). */ ++ if ((ctx->resp->options & RES_NOAAAA) == 0 ++ || buflen <= sizeof (HEADER)) ++ return false; ++ ++ /* The replacement A query is produced here. */ ++ struct ++ { ++ HEADER header; ++ unsigned char question[NS_MAXCDNAME + 4]; ++ } replacement; ++ memcpy (&replacement.header, buf, sizeof (replacement.header)); ++ ++ if (replacement.header.qr ++ || replacement.header.opcode != 0 ++ || replacement.header.rcode != 0 ++ || ntohs (replacement.header.qdcount) != 1 ++ || ntohs (replacement.header.ancount) != 0 ++ || ntohs (replacement.header.nscount) != 0) ++ /* Not a well-formed question. Let the core resolver code produce ++ the proper error. */ ++ return false; ++ ++ /* Disable EDNS0. */ ++ replacement.header.arcount = htons (0); ++ ++ /* Extract the QNAME. */ ++ int ret = ns_name_unpack (buf, buf + buflen, buf + sizeof (HEADER), ++ replacement.question, NS_MAXCDNAME); ++ if (ret < 0) ++ /* Format error. */ ++ return false; ++ ++ /* Compute the end of the question name. */ ++ const unsigned char *after_question = buf + sizeof (HEADER) + ret; ++ ++ /* Check that we are dealing with an AAAA query. */ ++ if (buf + buflen - after_question < 4 ++ || !qtype_matches (after_question, T_AAAA)) ++ return false; ++ ++ /* Find the place to store the type/class data in the replacement ++ query. */ ++ after_question = replacement.question; ++ /* This cannot fail because ns_name_unpack above produced a valid ++ domain name. */ ++ (void) ns_name_skip (&after_question, &replacement.question[NS_MAXCDNAME]); ++ unsigned char *start_of_query = (unsigned char *) &replacement; ++ const unsigned char *end_of_query = after_question + 4; ++ ++ /* Produce an A/IN query. */ ++ { ++ unsigned char *p = (unsigned char *) after_question; ++ p[0] = 0; ++ p[1] = T_A; ++ p[2] = 0; ++ p[3] = C_IN; ++ } ++ ++ /* Clear the output buffer, to avoid reading undefined data when ++ rewriting the result from A to AAAA. */ ++ memset (ans, 0, anssiz); ++ ++ /* Always perform the message translation, independent of the error ++ code. */ ++ ret = __res_context_send (ctx, ++ start_of_query, end_of_query - start_of_query, ++ NULL, 0, ans, anssiz, ++ NULL, NULL, NULL, NULL, NULL); ++ ++ /* Patch in the AAAA question type if there is room and the A query ++ type was received. */ ++ after_question = ans + sizeof (HEADER); ++ if (ns_name_skip (&after_question, ans + anssiz) == 0 ++ && ans + anssiz - after_question >= 4 ++ && qtype_matches (after_question, T_A)) ++ { ++ ((unsigned char *) after_question)[1] = T_AAAA; ++ ++ /* Create an aligned copy of the header. Hide all data except ++ the question from the response. Put back the header. There is ++ no need to change the response code. The zero answer count turns ++ a positive response with data into a no-data response. */ ++ memcpy (&replacement.header, ans, sizeof (replacement.header)); ++ replacement.header.ancount = htons (0); ++ replacement.header.nscount = htons (0); ++ replacement.header.arcount = htons (0); ++ memcpy (ans, &replacement.header, sizeof (replacement.header)); ++ ++ /* Truncate the reply. */ ++ if (ret <= 0) ++ *result = ret; ++ else ++ *result = after_question - ans + 4; ++ } ++ ++ return true; ++} +diff --git a/resolv/res_debug.c b/resolv/res_debug.c +index 7681ad4639d8a7bc..43b3b1bfe4afdcaf 100644 +--- a/resolv/res_debug.c ++++ b/resolv/res_debug.c +@@ -615,6 +615,7 @@ p_option(u_long option) { + case RES_USE_DNSSEC: return "dnssec"; + case RES_NOTLDQUERY: return "no-tld-query"; + case RES_NORELOAD: return "no-reload"; ++ case RES_NOAAAA: return "no-aaaa"; + /* XXX nonreentrant */ + default: sprintf(nbuf, "?0x%lx?", (u_long)option); + return (nbuf); +diff --git a/resolv/res_init.c b/resolv/res_init.c +index bb99ddeec4d6d47f..20434bfe147a3fb5 100644 +--- a/resolv/res_init.c ++++ b/resolv/res_init.c +@@ -694,7 +694,8 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options) + { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY }, + { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY }, + { STRnLEN ("no-reload"), 0, RES_NORELOAD }, +- { STRnLEN ("use-vc"), 0, RES_USEVC } ++ { STRnLEN ("use-vc"), 0, RES_USEVC }, ++ { STRnLEN ("no-aaaa"), 0, RES_NOAAAA }, + }; + #define noptions (sizeof (options) / sizeof (options[0])) + for (int i = 0; i < noptions; ++i) +diff --git a/resolv/res_query.c b/resolv/res_query.c +index ebbe5a6a4ed86abe..d94966a47c3dac90 100644 +--- a/resolv/res_query.c ++++ b/resolv/res_query.c +@@ -204,10 +204,26 @@ __res_context_query (struct resolv_context *ctx, const char *name, + free (buf); + return (n); + } +- assert (answerp == NULL || (void *) *answerp == (void *) answer); +- n = __res_context_send (ctx, query1, nquery1, query2, nquery2, answer, +- anslen, answerp, answerp2, nanswerp2, resplen2, +- answerp2_malloced); ++ ++ /* Suppress AAAA lookups if required. __res_handle_no_aaaa ++ checks RES_NOAAAA first, so avoids parsing the ++ just-generated query packet in most cases. nss_dns avoids ++ using T_QUERY_A_AND_AAAA in RES_NOAAAA mode, so there is no ++ need to handle it here. */ ++ if (type == T_AAAA && __res_handle_no_aaaa (ctx, query1, nquery1, ++ answer, anslen, &n)) ++ /* There must be no second query for AAAA queries. The code ++ below is still needed to translate NODATA responses. */ ++ assert (query2 == NULL); ++ else ++ { ++ assert (answerp == NULL || (void *) *answerp == (void *) answer); ++ n = __res_context_send (ctx, query1, nquery1, query2, nquery2, ++ answer, anslen, ++ answerp, answerp2, nanswerp2, resplen2, ++ answerp2_malloced); ++ } ++ + if (use_malloc) + free (buf); + if (n < 0) { +diff --git a/resolv/res_send.c b/resolv/res_send.c +index 55e7fa438e7baac1..2e676bff0edf0cdc 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -550,8 +550,13 @@ context_send_common (struct resolv_context *ctx, + RES_SET_H_ERRNO (&_res, NETDB_INTERNAL); + return -1; + } +- int result = __res_context_send (ctx, buf, buflen, NULL, 0, ans, anssiz, +- NULL, NULL, NULL, NULL, NULL); ++ ++ int result; ++ if (__res_handle_no_aaaa (ctx, buf, buflen, ans, anssiz, &result)) ++ return result; ++ ++ result = __res_context_send (ctx, buf, buflen, NULL, 0, ans, anssiz, ++ NULL, NULL, NULL, NULL, NULL); + __resolv_context_put (ctx); + return result; + } +diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h +index 0878f6830f2a08ff..4564f6ba2f7202f5 100644 +--- a/resolv/resolv-internal.h ++++ b/resolv/resolv-internal.h +@@ -79,6 +79,14 @@ int __res_context_send (struct resolv_context *, const unsigned char *, int, + int, unsigned char **, unsigned char **, + int *, int *, int *) attribute_hidden; + ++/* Return true if the query has been handled in RES_NOAAAA mode. For ++ that, RES_NOAAAA must be active, and the question type must be AAAA. ++ The caller is expected to return *RESULT as the return value. */ ++bool __res_handle_no_aaaa (struct resolv_context *ctx, ++ const unsigned char *buf, int buflen, ++ unsigned char *ans, int anssiz, int *result) ++ attribute_hidden; ++ + /* Internal function similar to res_hostalias. */ + const char *__res_context_hostalias (struct resolv_context *, + const char *, char *, size_t); +diff --git a/resolv/resolv.h b/resolv/resolv.h +index 80a523e5e40982ad..0f7298f395a829d3 100644 +--- a/resolv/resolv.h ++++ b/resolv/resolv.h +@@ -135,6 +135,7 @@ struct res_sym { + #define RES_NOTLDQUERY 0x01000000 /* Do not look up unqualified name + as a TLD. */ + #define RES_NORELOAD 0x02000000 /* No automatic configuration reload. */ ++#define RES_NOAAAA 0x08000000 /* Suppress AAAA queries. */ + + #define RES_DEFAULT (RES_RECURSE|RES_DEFNAMES|RES_DNSRCH) + +diff --git a/resolv/tst-resolv-noaaaa.c b/resolv/tst-resolv-noaaaa.c +new file mode 100644 +index 0000000000000000..56b25f88a58ad286 +--- /dev/null ++++ b/resolv/tst-resolv-noaaaa.c +@@ -0,0 +1,533 @@ ++/* Test the RES_NOAAAA resolver option. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to keep track of the number of queries. */ ++static volatile unsigned int queries; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* Each test should only send one query. */ ++ ++queries; ++ TEST_COMPARE (queries, 1); ++ ++ /* AAAA queries are supposed to be disabled. */ ++ TEST_VERIFY (qtype != T_AAAA); ++ TEST_COMPARE (qclass, C_IN); ++ ++ /* The only other query type besides A is PTR. */ ++ if (qtype != T_A) ++ TEST_COMPARE (qtype, T_PTR); ++ ++ int an, ns, ar; ++ char *tail; ++ if (sscanf (qname, "an%d.ns%d.ar%d.%ms", &an, &ns, &ar, &tail) != 4) ++ FAIL_EXIT1 ("invalid QNAME: %s\n", qname); ++ TEST_COMPARE_STRING (tail, "example"); ++ free (tail); ++ ++ if (an < 0 || ns < 0 || ar < 0) ++ { ++ struct resolv_response_flags flags = { .rcode = NXDOMAIN, }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ ++ resolv_response_section (b, ns_s_an); ++ for (int i = 0; i < an; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, qtype, 60); ++ switch (qtype) ++ { ++ case T_A: ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ break; ++ ++ case T_PTR: ++ char *name = xasprintf ("ptr-%d", i); ++ resolv_response_add_name (b, name); ++ free (name); ++ break; ++ } ++ resolv_response_close_record (b); ++ } ++ ++ resolv_response_section (b, ns_s_ns); ++ for (int i = 0; i < ns; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, T_NS, 60); ++ char *name = xasprintf ("ns%d.example.net", i); ++ resolv_response_add_name (b, name); ++ free (name); ++ resolv_response_close_record (b); ++ } ++ ++ resolv_response_section (b, ns_s_ar); ++ int addr = 1; ++ for (int i = 0; i < ns; ++i) ++ { ++ char *name = xasprintf ("ns%d.example.net", i); ++ for (int j = 0; j < ar; ++j) ++ { ++ resolv_response_open_record (b, name, qclass, T_A, 60); ++ char ipv4[4] = {192, 0, 2, addr}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ resolv_response_close_record (b); ++ ++ resolv_response_open_record (b, name, qclass, T_AAAA, 60); ++ char ipv6[16] ++ = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, addr}; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ resolv_response_close_record (b); ++ ++ ++addr; ++ } ++ free (name); ++ } ++} ++ ++/* Number of modes. Lowest bit encodes *n* function vs implicit _res ++ argument. The mode numbers themselves are arbitrary. */ ++enum { mode_count = 8 }; ++ ++/* res_send-like modes do not perform error translation. */ ++enum { first_send_mode = 6 }; ++ ++static int ++libresolv_query (unsigned int mode, const char *qname, uint16_t qtype, ++ unsigned char *buf, size_t buflen) ++{ ++ int saved_errno = errno; ++ ++ TEST_VERIFY_EXIT (mode < mode_count); ++ ++ switch (mode) ++ { ++ case 0: ++ return res_query (qname, C_IN, qtype, buf, buflen); ++ case 1: ++ return res_nquery (&_res, qname, C_IN, qtype, buf, buflen); ++ case 2: ++ return res_search (qname, C_IN, qtype, buf, buflen); ++ case 3: ++ return res_nsearch (&_res, qname, C_IN, qtype, buf, buflen); ++ case 4: ++ return res_querydomain (qname, "", C_IN, qtype, buf, buflen); ++ case 5: ++ return res_nquerydomain (&_res, qname, "", C_IN, qtype, buf, buflen); ++ case 6: ++ { ++ unsigned char querybuf[512]; ++ int ret = res_mkquery (QUERY, qname, C_IN, qtype, ++ NULL, 0, NULL, querybuf, sizeof (querybuf)); ++ TEST_VERIFY_EXIT (ret > 0); ++ errno = saved_errno; ++ return res_send (querybuf, ret, buf, buflen); ++ } ++ case 7: ++ { ++ unsigned char querybuf[512]; ++ int ret = res_nmkquery (&_res, QUERY, qname, C_IN, qtype, ++ NULL, 0, NULL, querybuf, sizeof (querybuf)); ++ TEST_VERIFY_EXIT (ret > 0); ++ errno = saved_errno; ++ return res_nsend (&_res, querybuf, ret, buf, buflen); ++ } ++ } ++ __builtin_unreachable (); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ _res.options |= RES_NOAAAA; ++ ++ check_hostent ("an1.ns2.ar1.example", ++ gethostbyname ("an1.ns2.ar1.example"), ++ "name: an1.ns2.ar1.example\n" ++ "address: 192.0.2.1\n"); ++ queries = 0; ++ check_hostent ("an0.ns2.ar1.example", ++ gethostbyname ("an0.ns2.ar1.example"), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ check_hostent ("an-1.ns2.ar1.example", ++ gethostbyname ("an-1.ns2.ar1.example"), ++ "error: HOST_NOT_FOUND\n"); ++ queries = 0; ++ ++ check_hostent ("an1.ns2.ar1.example AF_INET", ++ gethostbyname2 ("an1.ns2.ar1.example", AF_INET), ++ "name: an1.ns2.ar1.example\n" ++ "address: 192.0.2.1\n"); ++ queries = 0; ++ check_hostent ("an0.ns2.ar1.example AF_INET", ++ gethostbyname2 ("an0.ns2.ar1.example", AF_INET), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ check_hostent ("an-1.ns2.ar1.example AF_INET", ++ gethostbyname2 ("an-1.ns2.ar1.example", AF_INET), ++ "error: HOST_NOT_FOUND\n"); ++ queries = 0; ++ ++ check_hostent ("an1.ns2.ar1.example AF_INET6", ++ gethostbyname2 ("an1.ns2.ar1.example", AF_INET6), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ check_hostent ("an0.ns2.ar1.example AF_INET6", ++ gethostbyname2 ("an0.ns2.ar1.example", AF_INET6), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ check_hostent ("an-1.ns2.ar1.example AF_INET6", ++ gethostbyname2 ("an-1.ns2.ar1.example", AF_INET6), ++ "error: HOST_NOT_FOUND\n"); ++ queries = 0; ++ ++ /* Multiple addresses. */ ++ check_hostent ("an2.ns0.ar0.example", ++ gethostbyname ("an2.ns0.ar0.example"), ++ "name: an2.ns0.ar0.example\n" ++ "address: 192.0.2.1\n" ++ "address: 192.0.2.2\n"); ++ queries = 0; ++ check_hostent ("an2.ns0.ar0.example AF_INET6", ++ gethostbyname2 ("an2.ns0.ar0.example", AF_INET6), ++ "error: NO_ADDRESS\n"); ++ queries = 0; ++ ++ /* getaddrinfo checks with one address. */ ++ struct addrinfo *ai; ++ int ret; ++ ret = getaddrinfo ("an1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an1.ns2.ar1.example (AF_INET)", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n"); ++ freeaddrinfo (ai); ++ queries = 0; ++ ret = getaddrinfo ("an1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET6, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an1.ns2.ar1.example (AF_INET6)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ret = getaddrinfo ("an1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an1.ns2.ar1.example (AF_UNSPEC)", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n"); ++ freeaddrinfo (ai); ++ queries = 0; ++ ++ /* getaddrinfo checks with three addresses. */ ++ ret = getaddrinfo ("an3.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an3.ns2.ar1.example (AF_INET)", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n" ++ "address: STREAM/TCP 192.0.2.2 80\n" ++ "address: STREAM/TCP 192.0.2.3 80\n"); ++ freeaddrinfo (ai); ++ queries = 0; ++ ret = getaddrinfo ("an3.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET6, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an3.ns2.ar1.example (AF_INET6)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ret = getaddrinfo ("an3.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an3.ns2.ar1.example (AF_UNSPEC)", ai, ret, ++ "address: STREAM/TCP 192.0.2.1 80\n" ++ "address: STREAM/TCP 192.0.2.2 80\n" ++ "address: STREAM/TCP 192.0.2.3 80\n"); ++ freeaddrinfo (ai); ++ queries = 0; ++ ++ /* getaddrinfo checks with no address. */ ++ ret = getaddrinfo ("an0.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an0.ns2.ar1.example (AF_INET)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ret = getaddrinfo ("an0.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET6, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an0.ns2.ar1.example (AF_INET6)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ret = getaddrinfo ("an0.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an-1.ns2.ar1.example (AF_UNSPEC)", ai, ret, ++ "error: No address associated with hostname\n"); ++ queries = 0; ++ ++ /* getaddrinfo checks with NXDOMAIN. */ ++ ret = getaddrinfo ("an-1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an-1.ns2.ar1.example (AF_INET)", ai, ret, ++ "error: Name or service not known\n"); ++ queries = 0; ++ ret = getaddrinfo ("an-1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_INET6, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an-1.ns2.ar1.example (AF_INET6)", ai, ret, ++ "error: Name or service not known\n"); ++ queries = 0; ++ ret = getaddrinfo ("an-1.ns2.ar1.example", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ check_addrinfo ("an-1.ns2.ar1.example (AF_UNSPEC)", ai, ret, ++ "error: Name or service not known\n"); ++ queries = 0; ++ ++ for (unsigned int mode = 0; mode < mode_count; ++mode) ++ { ++ unsigned char *buf; ++ int ret; ++ ++ /* Response for A. */ ++ buf = malloc (512); ++ ret = libresolv_query (mode, "an1.ns2.ar1.example", T_A, buf, 512); ++ TEST_VERIFY_EXIT (ret > 0); ++ check_dns_packet ("an1.ns2.ar1.example A", buf, ret, ++ "name: an1.ns2.ar1.example\n" ++ "address: 192.0.2.1\n"); ++ free (buf); ++ queries = 0; ++ ++ /* NODATA response for A. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an0.ns2.ar1.example", T_A, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, NO_ADDRESS); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, 0); ++ check_dns_packet ("an1.ns2.ar1.example A", buf, ret, ++ "name: an0.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NXDOMAIN response for A. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_A, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN); ++ check_dns_packet ("an1.ns2.ar1.example A", buf, ret, ++ "name: an-1.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* Response for PTR. */ ++ buf = malloc (512); ++ ret = libresolv_query (mode, "an1.ns2.ar1.example", T_PTR, buf, 512); ++ TEST_VERIFY_EXIT (ret > 0); ++ check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret, ++ "name: an1.ns2.ar1.example\n" ++ "data: an1.ns2.ar1.example PTR ptr-0\n"); ++ free (buf); ++ queries = 0; ++ ++ /* NODATA response for PTR. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an0.ns2.ar1.example", T_PTR, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, NO_ADDRESS); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, 0); ++ check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret, ++ "name: an0.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NXDOMAIN response for PTR. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_PTR, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN); ++ check_dns_packet ("an1.ns2.ar1.example PTR", buf, ret, ++ "name: an-1.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NODATA response for AAAA. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an1.ns2.ar1.example", T_AAAA, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, NO_ADDRESS); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, 0); ++ check_dns_packet ("an1.ns2.ar1.example A", buf, ret, ++ "name: an1.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NODATA response for AAAA (original is already NODATA). */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an0.ns2.ar1.example", T_AAAA, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, NO_ADDRESS); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, 0); ++ check_dns_packet ("an0.ns2.ar1.example A", buf, ret, ++ "name: an0.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ ++ /* NXDOMAIN response. */ ++ buf = malloc (512); ++ errno = 0; ++ ret = libresolv_query (mode, "an-1.ns2.ar1.example", T_AAAA, buf, 512); ++ if (mode < first_send_mode) ++ { ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, 0); ++ TEST_COMPARE (h_errno, HOST_NOT_FOUND); ++ } ++ else ++ { ++ TEST_VERIFY_EXIT (ret > 0); ++ TEST_COMPARE (((HEADER *)buf)->rcode, NXDOMAIN); ++ check_dns_packet ("an-1.ns2.ar1.example A", buf, ret, ++ "name: an-1.ns2.ar1.example\n"); ++ } ++ free (buf); ++ queries = 0; ++ } ++ ++ resolv_test_end (obj); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c +index a5061e6d4fb98311..7d8758a99e180d97 100644 +--- a/resolv/tst-resolv-res_init-skeleton.c ++++ b/resolv/tst-resolv-res_init-skeleton.c +@@ -129,6 +129,7 @@ print_resp (FILE *fp, res_state resp) + "single-request-reopen"); + print_option_flag (fp, &options, RES_NOTLDQUERY, "no-tld-query"); + print_option_flag (fp, &options, RES_NORELOAD, "no-reload"); ++ print_option_flag (fp, &options, RES_NOAAAA, "no-aaaa"); + fputc ('\n', fp); + if (options != 0) + fprintf (fp, "; error: unresolved option bits: 0x%x\n", options); +@@ -713,6 +714,15 @@ struct test_case test_cases[] = + "nameserver 192.0.2.1\n" + "; nameserver[0]: [192.0.2.1]:53\n" + }, ++ {.name = "no-aaaa flag", ++ .conf = "options no-aaaa\n" ++ "nameserver 192.0.2.1\n", ++ .expected = "options no-aaaa\n" ++ "search example.com\n" ++ "; search[0]: example.com\n" ++ "nameserver 192.0.2.1\n" ++ "; nameserver[0]: [192.0.2.1]:53\n" ++ }, + { NULL } + }; + diff --git a/SOURCES/glibc-rh2096189-3.patch b/SOURCES/glibc-rh2096189-3.patch new file mode 100644 index 0000000..604afa4 --- /dev/null +++ b/SOURCES/glibc-rh2096189-3.patch @@ -0,0 +1,44 @@ +commit 77536da3dea5af4d1859e4e754f07f47cf8d7d4c +Author: Florian Weimer +Date: Fri Jun 24 19:38:14 2022 +0200 + + resolv/tst-resolv-noaaaa: Support building for older C standards + + This avoids a compilation error: + + tst-resolv-noaaaa.c: In function 'response': + tst-resolv-noaaaa.c:74:11: error: a label can only be part of a statement and a declaration is not a statement + char ipv4[4] = {192, 0, 2, i + 1}; + ^~~~ + tst-resolv-noaaaa.c:79:11: error: a label can only be part of a statement and a declaration is not a statement + char *name = xasprintf ("ptr-%d", i); + ^~~~ + +diff --git a/resolv/tst-resolv-noaaaa.c b/resolv/tst-resolv-noaaaa.c +index 56b25f88a58ad286..6e0c6b6fb809e245 100644 +--- a/resolv/tst-resolv-noaaaa.c ++++ b/resolv/tst-resolv-noaaaa.c +@@ -71,14 +71,18 @@ response (const struct resolv_response_context *ctx, + switch (qtype) + { + case T_A: +- char ipv4[4] = {192, 0, 2, i + 1}; +- resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ { ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } + break; + + case T_PTR: +- char *name = xasprintf ("ptr-%d", i); +- resolv_response_add_name (b, name); +- free (name); ++ { ++ char *name = xasprintf ("ptr-%d", i); ++ resolv_response_add_name (b, name); ++ free (name); ++ } + break; + } + resolv_response_close_record (b); diff --git a/SOURCES/glibc-rh2104907.patch b/SOURCES/glibc-rh2104907.patch new file mode 100644 index 0000000..3a65f18 --- /dev/null +++ b/SOURCES/glibc-rh2104907.patch @@ -0,0 +1,14 @@ +diff --git a/localedata/SUPPORTED b/localedata/SUPPORTED +index a4bf79c6a6e6401b..fdf15fddf5178319 100644 +--- a/localedata/SUPPORTED ++++ b/localedata/SUPPORTED +@@ -159,7 +159,8 @@ en_SG/ISO-8859-1 \ + en_US.UTF-8/UTF-8 \ + en_US/ISO-8859-1 \ + en_US.ISO-8859-15/ISO-8859-15 \ +-en_US@ampm.UTF-8/UTF-8 \ ++en_US@ampm/UTF-8 \ ++en_US.UTF-8@ampm/UTF-8 \ + en_ZA.UTF-8/UTF-8 \ + en_ZA/ISO-8859-1 \ + en_ZM/UTF-8 \ diff --git a/SOURCES/glibc-rh2119304-1.patch b/SOURCES/glibc-rh2119304-1.patch new file mode 100644 index 0000000..a76e1bf --- /dev/null +++ b/SOURCES/glibc-rh2119304-1.patch @@ -0,0 +1,49 @@ +Downstream-only patch to move the recently added members (from +glibc-rh2047981-5.patch and glibc-rh2047981-6.patch) to the end +of _rtld_global_ro. This avoids changing the offset of +GLRO (dl_naudit). + +Without this change, the audit invocation loop in the old +__libc_start_main function in a not-yet-updated version of libc.so.6 +reads a non-zero garbage value for GLRO (dl_naudit), assumes that +auditing is active, and reads further garbage pointers, leading to +to a crash. Preserving the old offset of GLRO (dl_naudit) avoids +that. This works because RPM updates /lib64/ld-* before +/lib64/libc.so.6 because it sorts earlier (except on POWER9 due +to the glibc-hwcaps/power9 multilib). + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 9dec9e3d3b6d6aa2..5e56550a4d556fa7 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -648,6 +648,15 @@ struct rtld_global_ro + void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen, + Lmid_t nsid, int argc, char *argv[], char *env[]); + void (*_dl_close) (void *map); ++ void *(*_dl_tls_get_addr_soft) (struct link_map *); ++#ifdef HAVE_DL_DISCOVER_OSVERSION ++ int (*_dl_discover_osversion) (void); ++#endif ++ ++ /* List of auditing interfaces. */ ++ struct audit_ifaces *_dl_audit; ++ unsigned int _dl_naudit; ++ + /* libdl in a secondary namespace (after dlopen) must use + _dl_catch_error from the main namespace, so it has to be + exported in some way. */ +@@ -657,14 +666,6 @@ struct rtld_global_ro + /* libdl in a secondary namespace must use free from the base + namespace. */ + void (*_dl_error_free) (void *); +- void *(*_dl_tls_get_addr_soft) (struct link_map *); +-#ifdef HAVE_DL_DISCOVER_OSVERSION +- int (*_dl_discover_osversion) (void); +-#endif +- +- /* List of auditing interfaces. */ +- struct audit_ifaces *_dl_audit; +- unsigned int _dl_naudit; + }; + # define __rtld_global_attribute__ + # if IS_IN (rtld) diff --git a/SOURCES/glibc-rh2119304-2.patch b/SOURCES/glibc-rh2119304-2.patch new file mode 100644 index 0000000..a1e121b --- /dev/null +++ b/SOURCES/glibc-rh2119304-2.patch @@ -0,0 +1,202 @@ +commit 5ecc98241229d494aaad23a4a3fe106fe11e1f40 +Author: Florian Weimer +Date: Thu Aug 25 16:34:20 2022 +0200 + + s390: Move hwcaps/platform names out of _rtld_global_ro + + Changes to these arrays are often backported to stable releases, + but additions to these arrays shift the offsets of the following + _rltd_global_ro members, thus breaking the GLIBC_PRIVATE ABI. + + Obviously, this change is itself an internal ABI break, but at least + it will avoid further ABI breaks going forward. + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/s390/Makefile + (missing lazy binding test downstream) + +diff --git a/sysdeps/s390/Makefile b/sysdeps/s390/Makefile +index 5c8e1170b4d799ba..ea453ba87646c95a 100644 +--- a/sysdeps/s390/Makefile ++++ b/sysdeps/s390/Makefile +@@ -42,6 +42,10 @@ $(modpfx)gconv-modules-s390.conf: ../sysdeps/s390/gconv-modules-s390.conf \ + cp $< $@ + endif + ++ifeq ($(subdir),elf) ++sysdep-dl-routines += dl-procinfo-s390 ++endif ++ + ifeq ($(subdir),string) + sysdep_routines += bzero memset memset-z900 \ + memcmp memcmp-z900 \ +diff --git a/sysdeps/s390/dl-procinfo-s390.c b/sysdeps/s390/dl-procinfo-s390.c +new file mode 100644 +index 0000000000000000..559f3827936cd017 +--- /dev/null ++++ b/sysdeps/s390/dl-procinfo-s390.c +@@ -0,0 +1,32 @@ ++/* Data for s390 version of processor capability information. ++ Copyright (C) 2006-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++const char _dl_s390_cap_flags[_DL_HWCAP_COUNT][9] = ++ { ++ "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", ++ "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt", ++ "vxp2", "nnpa", "pcimio", "sie" ++ }; ++ ++const char _dl_s390_platforms[_DL_PLATFORMS_COUNT][7] = ++ { ++ "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15", ++ "z16" ++ }; +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index 85108943d0e79f29..f928b485609a3b8a 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -17,66 +17,10 @@ + License along with the GNU C Library; if not, see + . */ + +-/* This information must be kept in sync with the _DL_HWCAP_COUNT and +- _DL_PLATFORM_COUNT definitions in procinfo.h. +- +- If anything should be added here check whether the size of each string +- is still ok with the given array size. +- +- All the #ifdefs in the definitions are quite irritating but +- necessary if we want to avoid duplicating the information. There +- are three different modes: +- +- - PROCINFO_DECL is defined. This means we are only interested in +- declarations. +- +- - PROCINFO_DECL is not defined: +- +- + if SHARED is defined the file is included in an array +- initializer. The .element = { ... } syntax is needed. +- +- + if SHARED is not defined a normal array initialization is +- needed. +- */ +- +-#ifndef PROCINFO_CLASS +-# define PROCINFO_CLASS +-#endif +- +-#if !defined PROCINFO_DECL && defined SHARED +- ._dl_s390_cap_flags +-#else +-PROCINFO_CLASS const char _dl_s390_cap_flags[23][9] +-#endif +-#ifndef PROCINFO_DECL +-= { +- "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", +- "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt", +- "vxp2", "nnpa", "pcimio", "sie" +- } +-#endif +-#if !defined SHARED || defined PROCINFO_DECL +-; +-#else +-, +-#endif +- +-#if !defined PROCINFO_DECL && defined SHARED +- ._dl_s390_platforms +-#else +-PROCINFO_CLASS const char _dl_s390_platforms[11][7] +-#endif +-#ifndef PROCINFO_DECL +-= { +- "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15", +- "z16" +- } +-#endif +-#if !defined SHARED || defined PROCINFO_DECL +-; +-#else +-, +-#endif ++/* The hwcap and platform strings are now in ++ sysdeps/s390/dl-procinfo-s390.c. */ + ++/* Needed by sysdeps/unix/sysv/linux/dl-vdso-setup.c (as included from ++ sysdeps/generic/ldsodefs.h). */ + #undef PROCINFO_DECL + #undef PROCINFO_CLASS +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index f2b2c9ac1bb7239b..5eb2c0a39fcff520 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -22,8 +22,10 @@ + #include + + #define _DL_HWCAP_COUNT 23 ++extern const char _dl_s390_cap_flags[_DL_HWCAP_COUNT][9] attribute_hidden; + + #define _DL_PLATFORMS_COUNT 11 ++extern const char _dl_s390_platforms[_DL_PLATFORMS_COUNT][7] attribute_hidden; + + /* The kernel provides up to 32 capability bits with elf_hwcap. */ + #define _DL_FIRST_PLATFORM 32 +@@ -79,7 +81,7 @@ static inline const char * + __attribute__ ((unused)) + _dl_hwcap_string (int idx) + { +- return GLRO(dl_s390_cap_flags)[idx]; ++ return _dl_s390_cap_flags[idx]; + }; + + static inline int +@@ -90,7 +92,7 @@ _dl_string_hwcap (const char *str) + + for (i = 0; i < _DL_HWCAP_COUNT; i++) + { +- if (strcmp (str, GLRO(dl_s390_cap_flags)[i]) == 0) ++ if (strcmp (str, _dl_s390_cap_flags[i]) == 0) + return i; + } + return -1; +@@ -105,7 +107,7 @@ _dl_string_platform (const char *str) + if (str != NULL) + for (i = 0; i < _DL_PLATFORMS_COUNT; ++i) + { +- if (strcmp (str, GLRO(dl_s390_platforms)[i]) == 0) ++ if (strcmp (str, _dl_s390_platforms[i]) == 0) + return _DL_FIRST_PLATFORM + i; + } + return -1; +diff --git a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h +index d1516a05e3042163..4aefd7eef14eaf52 100644 +--- a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h ++++ b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h +@@ -40,7 +40,7 @@ _dl_procinfo (unsigned int type, unsigned long int word) + + for (i = 0; i < _DL_HWCAP_COUNT; ++i) + if (word & (1UL << i)) +- _dl_printf (" %s", GLRO(dl_s390_cap_flags)[i]); ++ _dl_printf (" %s", _dl_s390_cap_flags[i]); + + _dl_printf ("\n"); + diff --git a/SOURCES/glibc-rh2119304-3.patch b/SOURCES/glibc-rh2119304-3.patch new file mode 100644 index 0000000..faaea99 --- /dev/null +++ b/SOURCES/glibc-rh2119304-3.patch @@ -0,0 +1,19 @@ +Downstream-only patch to preserve the 8.6.0 _rtld_global_ro ABI on s390x. + +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index f928b485609a3b8a..3f46b2785fafe51e 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -20,6 +20,12 @@ + /* The hwcap and platform strings are now in + sysdeps/s390/dl-procinfo-s390.c. */ + ++/* Dummy entries to preserve ABI. */ ++#if defined SHARED && defined PROCINFO_DECL ++const char _dl_s390_cap_flags_unused[23][9]; ++const char _dl_s390_platforms_unused[10][7]; ++#endif ++ + /* Needed by sysdeps/unix/sysv/linux/dl-vdso-setup.c (as included from + sysdeps/generic/ldsodefs.h). */ + #undef PROCINFO_DECL diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index 446f38d..848f4d1 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.28 %define glibcversion 2.28 -%define glibcrelease 189%{?dist} +%define glibcrelease 211%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -855,6 +855,119 @@ Patch660: glibc-rh2045063-2.patch Patch661: glibc-rh2045063-3.patch Patch662: glibc-rh2045063-4.patch Patch663: glibc-rh2045063-5.patch +Patch664: glibc-rh2054790.patch +Patch665: glibc-rh2037416-1.patch +Patch666: glibc-rh2037416-2.patch +Patch667: glibc-rh2037416-3.patch +Patch668: glibc-rh2037416-4.patch +Patch669: glibc-rh2037416-5.patch +Patch670: glibc-rh2037416-6.patch +Patch671: glibc-rh2037416-7.patch +Patch672: glibc-rh2037416-8.patch +Patch673: glibc-rh2033684-1.patch +Patch674: glibc-rh2033684-2.patch +Patch675: glibc-rh2033684-3.patch +Patch676: glibc-rh2033684-4.patch +Patch677: glibc-rh2033684-5.patch +Patch678: glibc-rh2033684-6.patch +Patch679: glibc-rh2033684-7.patch +Patch680: glibc-rh2033684-8.patch +Patch681: glibc-rh2033684-9.patch +Patch682: glibc-rh2033684-10.patch +Patch683: glibc-rh2033684-11.patch +Patch684: glibc-rh2033684-12.patch +Patch685: glibc-rh2063712.patch +Patch686: glibc-rh2063042.patch +Patch687: glibc-rh2071745.patch +Patch688: glibc-rh2065588-1.patch +Patch689: glibc-rh2065588-2.patch +Patch690: glibc-rh2065588-3.patch +Patch691: glibc-rh2065588-4.patch +Patch692: glibc-rh2065588-5.patch +Patch693: glibc-rh2065588-6.patch +Patch694: glibc-rh2065588-7.patch +Patch695: glibc-rh2065588-8.patch +Patch696: glibc-rh2065588-9.patch +Patch697: glibc-rh2065588-10.patch +Patch698: glibc-rh2065588-11.patch +Patch699: glibc-rh2065588-12.patch +Patch700: glibc-rh2065588-13.patch +Patch701: glibc-rh2072329.patch +Patch702: glibc-rh1982608.patch +Patch703: glibc-rh1961109.patch +Patch704: glibc-rh2086853.patch +Patch705: glibc-rh2077835.patch +Patch706: glibc-rh2089247-1.patch +Patch707: glibc-rh2089247-2.patch +Patch708: glibc-rh2089247-3.patch +Patch709: glibc-rh2089247-4.patch +Patch710: glibc-rh2089247-5.patch +Patch711: glibc-rh2089247-6.patch +Patch712: glibc-rh2091553.patch +Patch713: glibc-rh1888660.patch +Patch714: glibc-rh2096189-1.patch +Patch715: glibc-rh2096189-2.patch +Patch716: glibc-rh2096189-3.patch +Patch717: glibc-rh2080349-1.patch +Patch718: glibc-rh2080349-2.patch +Patch719: glibc-rh2080349-3.patch +Patch720: glibc-rh2080349-4.patch +Patch721: glibc-rh2080349-5.patch +Patch722: glibc-rh2080349-6.patch +Patch723: glibc-rh2080349-7.patch +Patch724: glibc-rh2080349-8.patch +Patch725: glibc-rh2080349-9.patch +Patch727: glibc-rh2047981-1.patch +Patch728: glibc-rh2047981-2.patch +Patch729: glibc-rh2047981-3.patch +Patch730: glibc-rh2047981-4.patch +Patch731: glibc-rh2047981-5.patch +Patch732: glibc-rh2047981-6.patch +Patch733: glibc-rh2047981-7.patch +Patch734: glibc-rh2047981-8.patch +Patch735: glibc-rh2047981-9.patch +Patch736: glibc-rh2047981-10.patch +Patch737: glibc-rh2047981-11.patch +Patch738: glibc-rh2047981-12.patch +Patch739: glibc-rh2047981-13.patch +Patch740: glibc-rh2047981-14.patch +Patch741: glibc-rh2047981-15.patch +Patch742: glibc-rh2047981-16.patch +Patch743: glibc-rh2047981-17.patch +Patch744: glibc-rh2047981-18.patch +Patch745: glibc-rh2047981-19.patch +Patch746: glibc-rh2047981-20.patch +Patch747: glibc-rh2047981-21.patch +Patch748: glibc-rh2047981-22.patch +Patch749: glibc-rh2047981-23.patch +Patch750: glibc-rh2047981-24.patch +Patch751: glibc-rh2047981-25.patch +Patch752: glibc-rh2047981-26.patch +Patch753: glibc-rh2047981-27.patch +Patch754: glibc-rh2047981-28.patch +Patch755: glibc-rh2047981-29.patch +Patch756: glibc-rh2047981-30.patch +Patch757: glibc-rh2047981-31.patch +Patch758: glibc-rh2047981-32.patch +Patch759: glibc-rh2047981-33.patch +Patch760: glibc-rh2047981-34.patch +Patch761: glibc-rh2047981-35.patch +Patch762: glibc-rh2047981-36.patch +Patch763: glibc-rh2047981-37.patch +Patch764: glibc-rh2047981-38.patch +Patch766: glibc-rh2047981-39.patch +Patch767: glibc-rh2047981-40.patch +Patch768: glibc-rh2047981-41.patch +Patch769: glibc-rh2047981-42.patch +Patch770: glibc-rh2047981-43.patch +Patch771: glibc-rh2047981-44.patch +Patch772: glibc-rh2047981-45.patch +Patch773: glibc-rh2047981-46.patch +Patch774: glibc-rh2047981-47.patch +Patch775: glibc-rh2104907.patch +Patch776: glibc-rh2119304-1.patch +Patch777: glibc-rh2119304-2.patch +Patch778: glibc-rh2119304-3.patch ############################################################################## # Continued list of core "glibc" package information: @@ -1746,6 +1859,20 @@ $olddir/build-%{target}/testrun.sh \ # default locale-archive without modification, and leaving compiled # locales as they are (without inclusion into the archive). cp locale-archive{,.tmpl} + +# Almost half the LC_CTYPE files in langpacks are identical to the C.utf8 +# variant which is installed by default. When we keep them as hardlinks, +# each langpack ends up retaining a copy. If we convert these to symbolic +# links instead, we save ~350K each when they get installed that way. +# +# LC_MEASUREMENT and LC_PAPER also have several duplicates but we don't +# bother with these because they are only ~30 bytes each. +pushd %{glibc_sysroot}/usr/lib/locale +for f in $(find eo *_* -samefile C.utf8/LC_CTYPE); do + rm $f && ln -s '../C.utf8/LC_CTYPE' $f +done +popd + # Create the file lists for the language specific sub-packages: for i in eo *_* do @@ -2054,7 +2181,7 @@ chmod 0444 master.filelist # - All the libnss files (we add back the ones we want later). # - All bench test binaries. # - The aux-cache, since it's handled specially in the files section. -# - The build-locale-archive binary since it's in the common package. +# - The build-locale-archive binary since it's in the all-langpacks package. # - Extra gconv modules. We add the required modules later. cat master.filelist \ | grep -v \ @@ -2179,13 +2306,15 @@ grep '%{_libdir}/lib.*\.a' < master.filelist \ ############################################################################### # All of the bin and certain sbin files go into the common package except -# iconvconfig which needs to go in glibc. Likewise nscd is excluded because +# iconvconfig which needs to go in glibc, and build-locale-archive which +# needs to go into glibc-all-langpacks. Likewise nscd is excluded because # it goes in nscd. The iconvconfig binary is kept in the main glibc package # because we use it in the post-install scriptlet to rebuild the # gconv-modules.cache. grep '%{_prefix}/bin' master.filelist >> common.filelist grep '%{_prefix}/sbin' master.filelist \ | grep -v '%{_prefix}/sbin/iconvconfig' \ + | grep -v '%{_prefix}/sbin/build-locale-archive' \ | grep -v 'nscd' >> common.filelist # All of the files under share go into the common package since they should be # multilib-independent. @@ -2201,9 +2330,6 @@ grep '%{_prefix}/share' master.filelist \ -e '%{_docdir}' \ >> common.filelist -# Add the binary to build locales to the common subpackage. -echo '%{_prefix}/sbin/build-locale-archive' >> common.filelist - ############################################################################### # nscd ############################################################################### @@ -2613,6 +2739,8 @@ fi %files all-langpacks %attr(0644,root,root) %verify(not md5 size mtime) %{_prefix}/lib/locale/locale-archive.tmpl %attr(0644,root,root) %verify(not md5 size mtime mode) %ghost %{_prefix}/lib/locale/locale-archive +# build-locale-archive re-generates locale-archive during install/upgrade/downgrade +%attr(0700,root,root) %{_prefix}/sbin/build-locale-archive %files locale-source %dir %{_prefix}/share/i18n/locales @@ -2670,6 +2798,75 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Thu Aug 25 2022 Florian Weimer - 2.28-211 +- Preserve GLRO (dl_naudit) internal ABI (#2119304) +- Avoid s390x ABI change due to z16 recognition on s390x (#2119304) + +* Tue Aug 23 2022 Arjun Shankar - 2.28-210 +- Fix locale en_US@ampm (#2104907) + +* Fri Jul 22 2022 Carlos O'Donell - 2.28-209 +- Improve dynamic loader auditing interface (LD_AUDIT) (#2047981) +- Add dlinfo() API support for RTLD_DI_PHDR (#2097898) + +* Fri Jul 15 2022 Patsy Griffin - 2.28-208 +- Update syscall-names.list to Linux 5.18. (#2080349) + +* Fri Jun 24 2022 Florian Weimer - 2.28-207 +- Add the no-aaaa DNS stub resolver option (#2096189) + +* Thu Jun 9 2022 Arjun Shankar - 2.28-206 +- Fix deadlocks in pthread_atfork handlers (#1888660) + +* Tue Jun 07 2022 DJ Delorie - 2.28-204 +- Increase tempnam randomness (#2089247) + +* Tue May 17 2022 Patsy Griffin - 2.28-203 +- 390x: Add support for IBM z16. (#2077835) + +* Mon May 16 2022 Siddhesh Poyarekar - 2.28-202 +- Ensure that condition in __glibc_fortify is a constant (#2086853) + +* Tue May 10 2022 Arjun Shankar - 2.28-201 +- Add missing MACRON to EBCDIC character sets (#1961109) + +* Wed May 4 2022 DJ Delorie - 2.28-200 +- Fix glob defects on certain XFS filesystems (#1982608) + +* Tue Apr 26 2022 Siddhesh Poyarekar - 2.28-199 +- Fix fortify false positive with mbsrtowcs and mbsnrtowcs (#2072329). + +* Fri Apr 22 2022 Carlos O'Donell - 2.28-198 +- Fix multi-threaded popen defect leading to segfault (#2065588) + +* Tue Apr 05 2022 Arjun Shankar - 2.28-197 +- timezone: Fix a test that causes occasional build failure (#2071745) + +* Tue Mar 15 2022 Siddhesh Poyarekar 2.28-196 +- Synchronize feature guards in fortified functions (#2063042) + +* Mon Mar 14 2022 Florian Weimer - 2.28-195 +- nss: Avoid clobbering errno in get*ent via dlopen (#2063712) + +* Fri Mar 11 2022 Siddhesh Poyarekar 2.28-194 +- Enable support for _FORTIFY_SOURCE=3 for gcc 12 and later (#2033684) + +* Wed Mar 9 2022 DJ Delorie - 2.28-193 +- memory operation A64FX SVE performance improvement (#2037416) + +* Mon Mar 07 2022 Arjun Shankar - 2.28-192 +- Move build-locale-archive to glibc-all-langpacks (#2057513) + +* Mon Mar 07 2022 Arjun Shankar - 2.28-191 +- Fix build-locale-archive to handle symbolic links (#2054790) + +* Fri Mar 04 2022 Arjun Shankar - 2.28-190 +- Reduce installed size of some langpacks by de-duplicating LC_CTYPE (#2054790) +- Fix localedef so it can handle symbolic links when generating locale-archive. + * Thu Jan 27 2022 Siddhesh Poyarekar - 2.28-189 - CVE-2021-3999: getcwd: align stack on clone in aarch64 and fix a memory leak (#2032281)