diff --git a/SOURCES/glibc-RHEL-21519.patch b/SOURCES/glibc-RHEL-21519.patch new file mode 100644 index 0000000..7e22998 --- /dev/null +++ b/SOURCES/glibc-RHEL-21519.patch @@ -0,0 +1,112 @@ +commit 849274d48fc59bfa6db3c713c8ced8026b20f3b7 +Author: Florian Weimer +Date: Thu Nov 16 19:55:35 2023 +0100 + + elf: Fix force_first handling in dlclose (bug 30981) + + The force_first parameter was ineffective because the dlclose'd + object was not necessarily the first in the maps array. Also + enable force_first handling unconditionally, regardless of namespace. + The initial object in a namespace should be destructed first, too. + + The _dl_sort_maps_dfs function had early returns for relocation + dependency processing which broke force_first handling, too, and + this is fixed in this change as well. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 22225efb3226c3e1..16a39f5bf17b440f 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -182,6 +182,16 @@ _dl_close_worker (struct link_map *map, bool force) + } + assert (idx == nloaded); + ++ /* Put the dlclose'd map first, so that its destructor runs first. ++ The map variable is NULL after a retry. */ ++ if (map != NULL) ++ { ++ maps[map->l_idx] = maps[0]; ++ maps[map->l_idx]->l_idx = map->l_idx; ++ maps[0] = map; ++ maps[0]->l_idx = 0; ++ } ++ + /* Keep track of the lowest index link map we have covered already. */ + int done_index = -1; + while (++done_index < nloaded) +@@ -255,9 +265,10 @@ _dl_close_worker (struct link_map *map, bool force) + } + } + +- /* Sort the entries. We can skip looking for the binary itself which is +- at the front of the search list for the main namespace. */ +- _dl_sort_maps (maps, nloaded, (nsid == LM_ID_BASE), true); ++ /* Sort the entries. Unless retrying, the maps[0] object (the ++ original argument to dlclose) needs to remain first, so that its ++ destructor runs first. */ ++ _dl_sort_maps (maps, nloaded, /* force_first */ map != NULL, true); + + /* Call all termination functions at once. */ + bool unload_any = false; +@@ -768,7 +779,11 @@ _dl_close_worker (struct link_map *map, bool force) + /* Recheck if we need to retry, release the lock. */ + out: + if (dl_close_state == rerun) +- goto retry; ++ { ++ /* The map may have been deallocated. */ ++ map = NULL; ++ goto retry; ++ } + + dl_close_state = not_pending; + } +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index aeb79b40b45054c0..c17ac325eca658ef 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -260,13 +260,12 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + The below memcpy is not needed in the do_reldeps case here, + since we wrote back to maps[] during DFS traversal. */ + if (maps_head == maps) +- return; ++ break; + } + assert (maps_head == maps); +- return; + } +- +- memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); ++ else ++ memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); + + /* Skipping the first object at maps[0] is not valid in general, + since traversing along object dependency-links may "find" that +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +index 4bf9052db16fb352..cf6453e9eb85ac65 100644 +--- a/elf/dso-sort-tests-1.def ++++ b/elf/dso-sort-tests-1.def +@@ -56,14 +56,16 @@ output: b>a>{}b->c->d order). +-# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based +-# dynamic_sort=2 algorithm does, although it is still arguable whether going +-# beyond spec to do this is the right thing to do. ++# The older dynamic_sort=1 algorithm originally did not achieve this, ++# but this was a bug in the way _dl_sort_maps was called from _dl_close_worker, ++# effectively disabling proper force_first handling. ++# The new dynamic_sort=2 algorithm shows the effect of the simpler force_first ++# handling: the a object is simply moved to the front. + # The below expected outputs are what the two algorithms currently produce + # respectively, for regression testing purposes. + tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c +-output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[ +Date: Mon Nov 27 11:28:07 2023 +0100 + + elf: In _dl_relocate_object, skip processing if object is relocated + + This is just a minor optimization. It also makes it more obvious that + _dl_relocate_object can be called multiple times. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index 7a84b1fa8c3a7fdd..a80a54fb013adab5 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -165,6 +165,9 @@ void + _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + int reloc_mode, int consider_profiling) + { ++ if (l->l_relocated) ++ return; ++ + struct textrels + { + caddr_t start; +@@ -202,9 +205,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + # define consider_symbind 0 + #endif + +- if (l->l_relocated) +- return; +- + /* If DT_BIND_NOW is set relocate all references in this object. We + do not do this if we are profiling, of course. */ + // XXX Correct for auditing? diff --git a/SOURCES/glibc-RHEL-21522-2.patch b/SOURCES/glibc-RHEL-21522-2.patch new file mode 100644 index 0000000..f42374b --- /dev/null +++ b/SOURCES/glibc-RHEL-21522-2.patch @@ -0,0 +1,121 @@ +commit a74c2e1cbc8673dd7e97aae2f2705392e2ccc3f6 +Author: Florian Weimer +Date: Mon Nov 27 11:28:10 2023 +0100 + + elf: Introduce the _dl_open_relocate_one_object function + + It is extracted from dl_open_worker_begin. + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index e82e53ff8b38fa11..1505fdb73088dcdb 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -466,6 +466,50 @@ activate_nodelete (struct link_map *new) + } + } + ++/* Relocate the object L. *RELOCATION_IN_PROGRESS controls whether ++ the debugger is notified of the start of relocation processing. */ ++static void ++_dl_open_relocate_one_object (struct dl_open_args *args, struct r_debug *r, ++ struct link_map *l, int reloc_mode, ++ bool *relocation_in_progress) ++{ ++ if (l->l_real->l_relocated) ++ return; ++ ++ if (!*relocation_in_progress) ++ { ++ /* Notify the debugger that relocations are about to happen. */ ++ LIBC_PROBE (reloc_start, 2, args->nsid, r); ++ *relocation_in_progress = true; ++ } ++ ++#ifdef SHARED ++ if (__glibc_unlikely (GLRO(dl_profile) != NULL)) ++ { ++ /* If this here is the shared object which we want to profile ++ make sure the profile is started. We can find out whether ++ this is necessary or not by observing the `_dl_profile_map' ++ variable. If it was NULL but is not NULL afterwards we must ++ start the profiling. */ ++ struct link_map *old_profile_map = GL(dl_profile_map); ++ ++ _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1); ++ ++ if (old_profile_map == NULL && GL(dl_profile_map) != NULL) ++ { ++ /* We must prepare the profiling. */ ++ _dl_start_profile (); ++ ++ /* Prevent unloading the object. */ ++ GL(dl_profile_map)->l_nodelete_active = true; ++ } ++ } ++ else ++#endif ++ _dl_relocate_object (l, l->l_scope, reloc_mode, 0); ++} ++ ++ + /* struct dl_init_args and call_dl_init are used to call _dl_init with + exception handling disabled. */ + struct dl_init_args +@@ -638,7 +682,7 @@ dl_open_worker_begin (void *a) + } + while (l != NULL); + +- int relocation_in_progress = 0; ++ bool relocation_in_progress = false; + + /* Perform relocation. This can trigger lazy binding in IFUNC + resolvers. For NODELETE mappings, these dependencies are not +@@ -649,44 +693,8 @@ dl_open_worker_begin (void *a) + are undefined anyway, so this is not a problem. */ + + for (unsigned int i = last; i-- > first; ) +- { +- l = new->l_initfini[i]; +- +- if (l->l_real->l_relocated) +- continue; +- +- if (! relocation_in_progress) +- { +- /* Notify the debugger that relocations are about to happen. */ +- LIBC_PROBE (reloc_start, 2, args->nsid, r); +- relocation_in_progress = 1; +- } +- +-#ifdef SHARED +- if (__glibc_unlikely (GLRO(dl_profile) != NULL)) +- { +- /* If this here is the shared object which we want to profile +- make sure the profile is started. We can find out whether +- this is necessary or not by observing the `_dl_profile_map' +- variable. If it was NULL but is not NULL afterwards we must +- start the profiling. */ +- struct link_map *old_profile_map = GL(dl_profile_map); +- +- _dl_relocate_object (l, l->l_scope, reloc_mode | RTLD_LAZY, 1); +- +- if (old_profile_map == NULL && GL(dl_profile_map) != NULL) +- { +- /* We must prepare the profiling. */ +- _dl_start_profile (); +- +- /* Prevent unloading the object. */ +- GL(dl_profile_map)->l_nodelete_active = true; +- } +- } +- else +-#endif +- _dl_relocate_object (l, l->l_scope, reloc_mode, 0); +- } ++ _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode, ++ &relocation_in_progress); + + /* This only performs the memory allocations. The actual update of + the scopes happens below, after failure is impossible. */ diff --git a/SOURCES/glibc-RHEL-21522-3.patch b/SOURCES/glibc-RHEL-21522-3.patch new file mode 100644 index 0000000..1471f87 --- /dev/null +++ b/SOURCES/glibc-RHEL-21522-3.patch @@ -0,0 +1,223 @@ +commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec +Author: Florian Weimer +Date: Mon Nov 27 11:28:13 2023 +0100 + + elf: Relocate libc.so early during startup and dlmopen (bug 31083) + + This makes it more likely that objects without dependencies can + use IFUNC resolvers in libc.so. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (differences in test backports) + elf/rtld.c + (removal of prelink support upstream) + +diff --git a/elf/Makefile b/elf/Makefile +index 634c3113227d64a6..6f0f36cdfe3961e8 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -386,6 +386,8 @@ tests += \ + tst-nodelete2 \ + tst-nodelete-dlclose \ + tst-nodelete-opened \ ++ tst-nodeps1 \ ++ tst-nodeps2 \ + tst-noload \ + tst-null-argv \ + tst-relsort1 \ +@@ -740,6 +742,8 @@ modules-names = \ + tst-nodelete-dlclose-dso \ + tst-nodelete-dlclose-plugin \ + tst-nodelete-opened-lib \ ++ tst-nodeps1-mod \ ++ tst-nodeps2-mod \ + tst-null-argv-lib \ + tst-relsort1mod1 \ + tst-relsort1mod2 \ +@@ -886,8 +890,13 @@ modules-execstack-yes = tst-execstack-mod + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + + # filtmod1.so has a special rule +-modules-names-nobuild := filtmod1 \ +- tst-audit24bmod1 tst-audit24bmod2 ++modules-names-nobuild += \ ++ filtmod1 \ ++ tst-audit24bmod1 \ ++ tst-audit24bmod2 \ ++ tst-nodeps1-mod \ ++ tst-nodeps2-mod \ ++ # modules-names-nobuild + + tests += $(tests-static) + +@@ -2697,3 +2706,19 @@ $(objpfx)tst-dlmopen-twice: $(libdl) + $(objpfx)tst-dlmopen-twice.out: \ + $(objpfx)tst-dlmopen-twice-mod1.so \ + $(objpfx)tst-dlmopen-twice-mod2.so ++ ++# The object tst-nodeps1-mod.so has no explicit dependencies on libc.so. ++$(objpfx)tst-nodeps1-mod.so: $(objpfx)tst-nodeps1-mod.os ++ $(LINK.o) -nostartfiles -nostdlib -shared -o $@ $^ ++tst-nodeps1.so-no-z-defs = yes ++# Link libc.so before the test module with the IFUNC resolver reference. ++LDFLAGS-tst-nodeps1 = $(common-objpfx)libc.so $(objpfx)tst-nodeps1-mod.so ++$(objpfx)tst-nodeps1: $(objpfx)tst-nodeps1-mod.so ++# Reuse the tst-nodeps1 module. Link libc.so before the test module ++# with the IFUNC resolver reference. ++$(objpfx)tst-nodeps2-mod.so: $(common-objpfx)libc.so \ ++ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.os ++ $(LINK.o) -Wl,--no-as-needed -nostartfiles -nostdlib -shared -o $@ $^ ++$(objpfx)tst-nodeps2: $(libdl) ++$(objpfx)tst-nodeps2.out: \ ++ $(objpfx)tst-nodeps1-mod.so $(objpfx)tst-nodeps2-mod.so +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 1505fdb73088dcdb..6508b0ea545440b8 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -692,6 +692,17 @@ dl_open_worker_begin (void *a) + them. However, such relocation dependencies in IFUNC resolvers + are undefined anyway, so this is not a problem. */ + ++ /* Ensure that libc is relocated first. This helps with the ++ execution of IFUNC resolvers in libc, and matters only to newly ++ created dlmopen namespaces. Do not do this for static dlopen ++ because libc has relocations against ld.so, which may not have ++ been relocated at this point. */ ++#ifdef SHARED ++ if (GL(dl_ns)[args->nsid].libc_map != NULL) ++ _dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map, ++ reloc_mode, &relocation_in_progress); ++#endif ++ + for (unsigned int i = last; i-- > first; ) + _dl_open_relocate_one_object (args, r, new->l_initfini[i], reloc_mode, + &relocation_in_progress); +diff --git a/elf/rtld.c b/elf/rtld.c +index cd2cc4024a3581c2..502d2a1c58505d88 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2414,11 +2414,17 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + objects. We do not re-relocate the dynamic linker itself in this + loop because that could result in the GOT entries for functions we + call being changed, and that would break us. It is safe to relocate +- the dynamic linker out of order because it has no copy relocs (we +- know that because it is self-contained). */ ++ the dynamic linker out of order because it has no copy relocations. ++ Likewise for libc, which is relocated early to ensure that IFUNC ++ resolvers in libc work. */ + + int consider_profiling = GLRO(dl_profile) != NULL; + ++ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) ++ _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, ++ GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, ++ GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); ++ + /* If we are profiling we also must do lazy reloaction. */ + GLRO(dl_lazy) |= consider_profiling; + +diff --git a/elf/tst-nodeps1-mod.c b/elf/tst-nodeps1-mod.c +new file mode 100644 +index 0000000000000000..45c8e3c631251a89 +--- /dev/null ++++ b/elf/tst-nodeps1-mod.c +@@ -0,0 +1,25 @@ ++/* Test module with no libc.so dependency and string function references. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++/* Some references to libc symbols which are likely to have IFUNC ++ resolvers. If they do not, this module does not exercise bug 31083. */ ++void *memcpy_pointer = memcpy; ++void *memmove_pointer = memmove; ++void *memset_pointer = memset; +diff --git a/elf/tst-nodeps1.c b/elf/tst-nodeps1.c +new file mode 100644 +index 0000000000000000..1a8bde36cdb71446 +--- /dev/null ++++ b/elf/tst-nodeps1.c +@@ -0,0 +1,23 @@ ++/* Test initially loaded module with implicit libc.so dependency (bug 31083). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Testing happens before main. */ ++int ++main (void) ++{ ++} +diff --git a/elf/tst-nodeps2-mod.c b/elf/tst-nodeps2-mod.c +new file mode 100644 +index 0000000000000000..4913feee9b56e0e1 +--- /dev/null ++++ b/elf/tst-nodeps2-mod.c +@@ -0,0 +1 @@ ++/* Empty test module which depends on tst-nodeps1-mod.so. */ +diff --git a/elf/tst-nodeps2.c b/elf/tst-nodeps2.c +new file mode 100644 +index 0000000000000000..0bdc8eeb8cba3a99 +--- /dev/null ++++ b/elf/tst-nodeps2.c +@@ -0,0 +1,29 @@ ++/* Test dlmopen with implicit libc.so dependency (bug 31083). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-nodeps2-mod.so", RTLD_NOW); ++ xdlclose (handle); ++ return 0; ++} ++ ++#include diff --git a/SOURCES/glibc-RHEL-21522-4.patch b/SOURCES/glibc-RHEL-21522-4.patch new file mode 100644 index 0000000..ffa3ec5 --- /dev/null +++ b/SOURCES/glibc-RHEL-21522-4.patch @@ -0,0 +1,41 @@ +commit b3bee76c5f59498b9c189608f0a3132e2013fa1a +Author: Florian Weimer +Date: Fri Dec 8 09:51:34 2023 +0100 + + elf: Initialize GLRO(dl_lazy) before relocating libc in dynamic startup + + GLRO(dl_lazy) is used to set the parameters for the early + _dl_relocate_object call, so the consider_profiling setting has to + be applied before the call. + + Fixes commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec ("elf: Relocate + libc.so early during startup and dlmopen (bug 31083)"). + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/rtld.c + (removal of prelink support upstream) + +diff --git a/elf/rtld.c b/elf/rtld.c +index 502d2a1c58505d88..4f317a2a874e6af7 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2420,14 +2420,14 @@ ERROR: '%s': cannot process note segment.\n", _dl_argv[0]); + + int consider_profiling = GLRO(dl_profile) != NULL; + ++ /* If we are profiling we also must do lazy reloaction. */ ++ GLRO(dl_lazy) |= consider_profiling; ++ + if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) + _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, + GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, + GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); + +- /* If we are profiling we also must do lazy reloaction. */ +- GLRO(dl_lazy) |= consider_profiling; +- + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); + unsigned i = main_map->l_searchlist.r_nlist; diff --git a/SOURCES/glibc-RHEL-22441.patch b/SOURCES/glibc-RHEL-22441.patch new file mode 100644 index 0000000..1262624 --- /dev/null +++ b/SOURCES/glibc-RHEL-22441.patch @@ -0,0 +1,83 @@ +commit c00b984fcd53f679ca2dafcd1aee2c89836e6e73 +Author: Florian Weimer +Date: Tue Aug 29 08:28:31 2023 +0200 + + nscd: Skip unusable entries in first pass in prune_cache (bug 30800) + + Previously, if an entry was marked unusable for any reason, but had + not timed out yet, the assert would trigger. + + One way to get into such state is if a data change is detected during + re-validation of an entry. This causes the entry to be marked as not + usable. If exits nscd soon after that, then the clock jumps + backwards, and nscd restarted, the cache re-validation run after + startup triggers the removed assert. + + The change is more complicated than just the removal of the assert + because entries marked as not usable should be garbage-collected in + the second pass. To make this happen, it is necessary to update some + book-keeping data. + + Reviewed-by: DJ Delorie + +diff --git a/nscd/cache.c b/nscd/cache.c +index efe4214d953edb30..2fd3f78ebb567bbe 100644 +--- a/nscd/cache.c ++++ b/nscd/cache.c +@@ -371,8 +371,11 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + serv2str[runp->type], str, dh->timeout); + } + +- /* Check whether the entry timed out. */ +- if (dh->timeout < now) ++ /* Check whether the entry timed out. Timed out entries ++ will be revalidated. For unusable records, it is still ++ necessary to record that the bucket needs to be scanned ++ again below. */ ++ if (dh->timeout < now || !dh->usable) + { + /* This hash bucket could contain entries which need to + be looked at. */ +@@ -384,7 +387,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + /* We only have to look at the data of the first entries + since the count information is kept in the data part + which is shared. */ +- if (runp->first) ++ if (runp->first && dh->usable) + { + + /* At this point there are two choices: we reload the +@@ -400,9 +403,6 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + { + /* Remove the value. */ + dh->usable = false; +- +- /* We definitely have some garbage entries now. */ +- any = true; + } + else + { +@@ -414,18 +414,15 @@ prune_cache (struct database_dyn *table, time_t now, int fd) + + time_t timeout = readdfcts[runp->type] (table, runp, dh); + next_timeout = MIN (next_timeout, timeout); +- +- /* If the entry has been replaced, we might need +- cleanup. */ +- any |= !dh->usable; + } + } ++ ++ /* If the entry has been replaced, we might need cleanup. */ ++ any |= !dh->usable; + } + else +- { +- assert (dh->usable); +- next_timeout = MIN (next_timeout, dh->timeout); +- } ++ /* Entry has not timed out and is usable. */ ++ next_timeout = MIN (next_timeout, dh->timeout); + + run = runp->next; + } diff --git a/SOURCES/glibc-RHEL-22846.patch b/SOURCES/glibc-RHEL-22846.patch new file mode 100644 index 0000000..4179f74 --- /dev/null +++ b/SOURCES/glibc-RHEL-22846.patch @@ -0,0 +1,237 @@ +commit d0f07f7df8d9758c838674b70144ac73bcbd1634 +Author: Florian Weimer +Date: Tue May 30 13:25:50 2023 +0200 + + elf: Make more functions available for binding during dlclose (bug 30425) + + Previously, after destructors for a DSO have been invoked, ld.so refused + to bind against that DSO in all cases. Relax this restriction somewhat + if the referencing object is itself a DSO that is being unloaded. This + assumes that the symbol reference is not going to be stored anywhere. + + The situation in the test case can arise fairly easily with C++ and + objects that are built with different optimization levels and therefore + define different functions with vague linkage. + + Reviewed-by: Carlos O'Donell + +Conflicts: + elf/Makefile + (usual test differences, link test with -ldl) + +diff --git a/elf/Makefile b/elf/Makefile +index 6f0f36cdfe3961e8..ebf46a297d241d8f 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -362,6 +362,7 @@ tests += \ + tst-big-note \ + tst-debug1 \ + tst-deep1 \ ++ tst-dlclose-lazy \ + tst-dlmodcount \ + tst-dlmopen1 \ + tst-dlmopen3 \ +@@ -711,6 +712,8 @@ modules-names = \ + tst-deep1mod2 \ + tst-deep1mod3 \ + tst-dlmopen1mod \ ++ tst-dlclose-lazy-mod1 \ ++ tst-dlclose-lazy-mod2 \ + tst-dlmopen-dlerror-mod \ + tst-dlmopen-gethostbyname-mod \ + tst-dlmopen-twice-mod1 \ +@@ -2707,6 +2710,12 @@ $(objpfx)tst-dlmopen-twice.out: \ + $(objpfx)tst-dlmopen-twice-mod1.so \ + $(objpfx)tst-dlmopen-twice-mod2.so + ++LDFLAGS-tst-dlclose-lazy-mod1.so = -Wl,-z,lazy,--no-as-needed ++$(objpfx)tst-dlclose-lazy-mod1.so: $(objpfx)tst-dlclose-lazy-mod2.so ++$(objpfx)tst-dlclose-lazy: $(libdl) ++$(objpfx)tst-dlclose-lazy.out: \ ++ $(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so ++ + # The object tst-nodeps1-mod.so has no explicit dependencies on libc.so. + $(objpfx)tst-nodeps1-mod.so: $(objpfx)tst-nodeps1-mod.os + $(LINK.o) -nostartfiles -nostdlib -shared -o $@ $^ +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 47acd134600b44b5..9e8f14b8483f5eba 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -380,8 +380,25 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable) + continue; + +- /* Do not look into objects which are going to be removed. */ +- if (map->l_removed) ++ /* Do not look into objects which are going to be removed, ++ except when the referencing object itself is being removed. ++ ++ The second part covers the situation when an object lazily ++ binds to another object while running its destructor, but the ++ destructor of the other object has already run, so that ++ dlclose has set l_removed. It may not always be obvious how ++ to avoid such a scenario to programmers creating DSOs, ++ particularly if C++ vague linkage is involved and triggers ++ symbol interposition. ++ ++ Accepting these to-be-removed objects makes the lazy and ++ BIND_NOW cases more similar. (With BIND_NOW, the symbol is ++ resolved early, before the destructor call, so the issue does ++ not arise.). Behavior matches the constructor scenario: the ++ implementation allows binding to symbols of objects whose ++ constructors have not run. In fact, not doing this would be ++ mostly incompatible with symbol interposition. */ ++ if (map->l_removed && !(undef_map != NULL && undef_map->l_removed)) + continue; + + /* Print some debugging info if wanted. */ +diff --git a/elf/tst-dlclose-lazy-mod1.c b/elf/tst-dlclose-lazy-mod1.c +new file mode 100644 +index 0000000000000000..8439dc1925cc8b41 +--- /dev/null ++++ b/elf/tst-dlclose-lazy-mod1.c +@@ -0,0 +1,36 @@ ++/* Lazy binding during dlclose. Directly loaded module. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This function is called from exported_function below. It is only ++ defined in this module. The weak attribute mimics how G++ ++ implements vague linkage for C++. */ ++void __attribute__ ((weak)) ++lazily_bound_exported_function (void) ++{ ++} ++ ++/* Called from tst-dlclose-lazy-mod2.so. */ ++void ++exported_function (int call_it) ++{ ++ if (call_it) ++ /* Previous to the fix this would crash when called during dlclose ++ since symbols from the DSO were no longer available for binding ++ (bug 30425) after the DSO started being closed by dlclose. */ ++ lazily_bound_exported_function (); ++} +diff --git a/elf/tst-dlclose-lazy-mod2.c b/elf/tst-dlclose-lazy-mod2.c +new file mode 100644 +index 0000000000000000..767f69ffdb23a685 +--- /dev/null ++++ b/elf/tst-dlclose-lazy-mod2.c +@@ -0,0 +1,49 @@ ++/* Lazy binding during dlclose. Indirectly loaded module. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++void ++exported_function (int ignored) ++{ ++ /* This function is interposed from tst-dlclose-lazy-mod1.so and ++ thus never called. */ ++ abort (); ++} ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlclose-lazy-mod2.so constructor called"); ++ ++ /* Trigger lazy binding to the definition in ++ tst-dlclose-lazy-mod1.so, but not for ++ lazily_bound_exported_function in that module. */ ++ exported_function (0); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlclose-lazy-mod2.so destructor called"); ++ ++ /* Trigger the lazily_bound_exported_function call in ++ exported_function in tst-dlclose-lazy-mod1.so. */ ++ exported_function (1); ++} +diff --git a/elf/tst-dlclose-lazy.c b/elf/tst-dlclose-lazy.c +new file mode 100644 +index 0000000000000000..976a6bb6f64fa981 +--- /dev/null ++++ b/elf/tst-dlclose-lazy.c +@@ -0,0 +1,47 @@ ++/* Test lazy binding during dlclose (bug 30425). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This test re-creates a situation that can arise naturally for C++ ++ applications due to the use of vague linkage and differences in the ++ set of compiler-emitted functions. A function in ++ tst-dlclose-lazy-mod1.so (exported_function) interposes a function ++ in tst-dlclose-lazy-mod2.so. This function is called from the ++ destructor in tst-dlclose-lazy-mod2.so, after the destructor for ++ tst-dlclose-lazy-mod1.so has already completed. Prior to the fix ++ for bug 30425, this would lead to a lazy binding failure in ++ tst-dlclose-lazy-mod1.so because dlclose had already marked the DSO ++ as unavailable for binding (by setting l_removed). */ ++ ++#include ++#include ++#include ++ ++int ++main (void) ++{ ++ /* Load tst-dlclose-lazy-mod1.so, indirectly loading ++ tst-dlclose-lazy-mod2.so. */ ++ void *handle = xdlopen ("tst-dlclose-lazy-mod1.so", RTLD_GLOBAL | RTLD_LAZY); ++ ++ /* Invoke the destructor of tst-dlclose-lazy-mod2.so, which calls ++ into tst-dlclose-lazy-mod1.so after its destructor has been ++ called. */ ++ xdlclose (handle); ++ ++ return 0; ++} diff --git a/SOURCES/glibc-RHEL-22847.patch b/SOURCES/glibc-RHEL-22847.patch new file mode 100644 index 0000000..538a9d0 --- /dev/null +++ b/SOURCES/glibc-RHEL-22847.patch @@ -0,0 +1,27 @@ +commit ecc7c3deb9f347649c2078fcc0f94d4cedf92d60 +Author: Florian Weimer +Date: Tue Jan 2 14:36:17 2024 +0100 + + libio: Check remaining buffer size in _IO_wdo_write (bug 31183) + + The multibyte character needs to fit into the remaining buffer space, + not the already-written buffer space. Without the fix, we were never + moving the write pointer from the start of the buffer, always using + the single-character fallback buffer. + + Fixes commit 04b76b5aa8b2d1d19066e42dd1 ("Don't error out writing + a multibyte character to an unbuffered stream (bug 17522)"). + +diff --git a/libio/wfileops.c b/libio/wfileops.c +index d3deb34ba058ca39..6a6421f8880f9356 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -57,7 +57,7 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do) + char mb_buf[MB_LEN_MAX]; + char *write_base, *write_ptr, *buf_end; + +- if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf)) ++ if (fp->_IO_buf_end - fp->_IO_write_ptr < sizeof (mb_buf)) + { + /* Make sure we have room for at least one multibyte + character. */ diff --git a/SPECS/glibc.spec b/SPECS/glibc.spec index 691576b..c647b69 100644 --- a/SPECS/glibc.spec +++ b/SPECS/glibc.spec @@ -132,7 +132,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: %{glibcrelease}.7 +Release: %{glibcrelease}.12 # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -1053,6 +1053,14 @@ Patch865: glibc-RHEL-2435.patch Patch866: glibc-RHEL-2435-2.patch Patch867: glibc-RHEL-2423.patch Patch868: glibc-RHEL-3036.patch +Patch869: glibc-RHEL-21522-1.patch +Patch870: glibc-RHEL-21522-2.patch +Patch871: glibc-RHEL-21522-3.patch +Patch872: glibc-RHEL-21522-4.patch +Patch873: glibc-RHEL-21519.patch +Patch874: glibc-RHEL-22441.patch +Patch875: glibc-RHEL-22846.patch +Patch876: glibc-RHEL-22847.patch ############################################################################## # Continued list of core "glibc" package information: @@ -2883,6 +2891,21 @@ fi %files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared %changelog +* Mon Jan 29 2024 Florian Weimer - 2.28-236.12 +- Re-enable output buffering for wide stdio streams (RHEL-22847) + +* Mon Jan 29 2024 Florian Weimer - 2.28-236.11 +- Avoid lazy binding failures during dlclose (RHEL-22846) + +* Fri Jan 26 2024 Florian Weimer - 2.28-236.10 +- nscd: Skip unusable entries in first pass in prune_cache (RHEL-22441) + +* Fri Jan 26 2024 Florian Weimer - 2.28-236.9 +- Fix force-first handling in dlclose (RHEL-21519) + +* Fri Jan 26 2024 Florian Weimer - 2.28-236.8 +- Improve compatibility between underlinking and IFUNC resolvers (RHEL-21522) + * Wed Sep 20 2023 Siddhesh Poyarekar - 2.28-236.7 - CVE-2023-4911 glibc: buffer overflow in ld.so leading to privilege escalation (RHEL-3036)