Compare commits

..

No commits in common. "c8" and "c8" have entirely different histories.
c8 ... c8

209 changed files with 31 additions and 41904 deletions

View File

@ -159,8 +159,7 @@ 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 \
en_US.UTF-8@ampm/UTF-8 \
en_US@ampm.UTF-8/UTF-8 \
en_ZA.UTF-8/UTF-8 \
en_ZA/ISO-8859-1 \
en_ZM/UTF-8 \

View File

@ -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 || d_type == DT_LNK)
if (d_type == DT_UNKNOWN)
#endif
{
strcpy (stpcpy (stpcpy (fullname, fname), "/"),

View File

@ -1,112 +0,0 @@
commit 849274d48fc59bfa6db3c713c8ced8026b20f3b7
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Nov 16 19:55:35 2023 +0100
elf: Fix force_first handling in dlclose (bug 30981)
The force_first parameter was ineffective because the dlclose'd
object was not necessarily the first in the maps array. Also
enable force_first handling unconditionally, regardless of namespace.
The initial object in a namespace should be destructed first, too.
The _dl_sort_maps_dfs function had early returns for relocation
dependency processing which broke force_first handling, too, and
this is fixed in this change as well.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 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>{}<a<b
# relocation(dynamic) dependencies. While this is technically unspecified, the
# presumed reasonable practical behavior is for the destructor order to respect
# the static DT_NEEDED links (here this means the a->b->c->d order).
-# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based
-# dynamic_sort=2 algorithm does, although it is still arguable whether going
-# beyond spec to do this is the right thing to do.
+# The older dynamic_sort=1 algorithm originally did not achieve this,
+# but this was a bug in the way _dl_sort_maps was called from _dl_close_worker,
+# effectively disabling proper force_first handling.
+# The new dynamic_sort=2 algorithm shows the effect of the simpler force_first
+# handling: the a object is simply moved to the front.
# The below expected outputs are what the two algorithms currently produce
# respectively, for regression testing purposes.
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
-output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
-output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
+output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<b<c<d<g<f<e];}
+output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<g<f<b<c<d<e];}
# Test that even in the presence of dependency loops involving dlopen'ed
# object, that object is initialized last (and not unloaded prematurely).

View File

@ -1,35 +0,0 @@
commit b893410be304ddcea0bd43f537a13e8b18d37cf2
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Nov 27 11:28:07 2023 +0100
elf: In _dl_relocate_object, skip processing if object is relocated
This is just a minor optimization. It also makes it more obvious that
_dl_relocate_object can be called multiple times.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 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?

View File

@ -1,121 +0,0 @@
commit a74c2e1cbc8673dd7e97aae2f2705392e2ccc3f6
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Nov 27 11:28:10 2023 +0100
elf: Introduce the _dl_open_relocate_one_object function
It is extracted from dl_open_worker_begin.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 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. */

View File

@ -1,223 +0,0 @@
commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Nov 27 11:28:13 2023 +0100
elf: Relocate libc.so early during startup and dlmopen (bug 31083)
This makes it more likely that objects without dependencies can
use IFUNC resolvers in libc.so.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
elf/Makefile
(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
+ <https://www.gnu.org/licenses/>. */
+
+#include <string.h>
+
+/* Some references to libc symbols which are likely to have IFUNC
+ resolvers. If they do not, this module does not exercise bug 31083. */
+void *memcpy_pointer = memcpy;
+void *memmove_pointer = memmove;
+void *memset_pointer = memset;
diff --git a/elf/tst-nodeps1.c b/elf/tst-nodeps1.c
new file mode 100644
index 0000000000000000..1a8bde36cdb71446
--- /dev/null
+++ b/elf/tst-nodeps1.c
@@ -0,0 +1,23 @@
+/* Test initially loaded module with implicit libc.so dependency (bug 31083).
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* Testing happens before main. */
+int
+main (void)
+{
+}
diff --git a/elf/tst-nodeps2-mod.c b/elf/tst-nodeps2-mod.c
new file mode 100644
index 0000000000000000..4913feee9b56e0e1
--- /dev/null
+++ b/elf/tst-nodeps2-mod.c
@@ -0,0 +1 @@
+/* Empty test module which depends on tst-nodeps1-mod.so. */
diff --git a/elf/tst-nodeps2.c b/elf/tst-nodeps2.c
new file mode 100644
index 0000000000000000..0bdc8eeb8cba3a99
--- /dev/null
+++ b/elf/tst-nodeps2.c
@@ -0,0 +1,29 @@
+/* Test dlmopen with implicit libc.so dependency (bug 31083).
+ Copyright (C) 2023 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdlfcn.h>
+
+static int
+do_test (void)
+{
+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-nodeps2-mod.so", RTLD_NOW);
+ xdlclose (handle);
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -1,41 +0,0 @@
commit b3bee76c5f59498b9c189608f0a3132e2013fa1a
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Dec 8 09:51:34 2023 +0100
elf: Initialize GLRO(dl_lazy) before relocating libc in dynamic startup
GLRO(dl_lazy) is used to set the parameters for the early
_dl_relocate_object call, so the consider_profiling setting has to
be applied before the call.
Fixes commit 78ca44da0160a0b442f0ca1f253e3360f044b2ec ("elf: Relocate
libc.so early during startup and dlmopen (bug 31083)").
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
elf/rtld.c
(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;

View File

@ -1,83 +0,0 @@
commit c00b984fcd53f679ca2dafcd1aee2c89836e6e73
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Aug 29 08:28:31 2023 +0200
nscd: Skip unusable entries in first pass in prune_cache (bug 30800)
Previously, if an entry was marked unusable for any reason, but had
not timed out yet, the assert would trigger.
One way to get into such state is if a data change is detected during
re-validation of an entry. This causes the entry to be marked as not
usable. If exits nscd soon after that, then the clock jumps
backwards, and nscd restarted, the cache re-validation run after
startup triggers the removed assert.
The change is more complicated than just the removal of the assert
because entries marked as not usable should be garbage-collected in
the second pass. To make this happen, it is necessary to update some
book-keeping data.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/nscd/cache.c b/nscd/cache.c
index 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;
}

View File

@ -1,237 +0,0 @@
commit d0f07f7df8d9758c838674b70144ac73bcbd1634
Author: Florian Weimer <fweimer@redhat.com>
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 <carlos@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+/* 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+/* 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 <dlfcn.h>
+#include <support/xdlfcn.h>
+#include <support/check.h>
+
+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;
+}

View File

@ -1,27 +0,0 @@
commit ecc7c3deb9f347649c2078fcc0f94d4cedf92d60
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Jan 2 14:36:17 2024 +0100
libio: Check remaining buffer size in _IO_wdo_write (bug 31183)
The multibyte character needs to fit into the remaining buffer space,
not the already-written buffer space. Without the fix, we were never
moving the write pointer from the start of the buffer, always using
the single-character fallback buffer.
Fixes commit 04b76b5aa8b2d1d19066e42dd1 ("Don't error out writing
a multibyte character to an unbuffered stream (bug 17522)").
diff --git a/libio/wfileops.c b/libio/wfileops.c
index 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. */

View File

@ -1,347 +0,0 @@
Avoid UAF in getcanonname (CVE-2023-4806)
When an NSS plugin only implements the _gethostbyname2_r and
_getcanonname_r callbacks, getaddrinfo could use memory that was freed
during tmpbuf resizing, through h_name in a previous query response.
The backing store for res->at->name when doing a query with
gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in
gethosts during the query. For AF_INET6 lookup with AI_ALL |
AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second
for a v4 lookup. In this case, if the first call reallocates tmpbuf
enough number of times, resulting in a malloc, th->h_name (that
res->at->name refers to) ends up on a heap allocated storage in tmpbuf.
Now if the second call to gethosts also causes the plugin callback to
return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF
reference in res->at->name. This then gets dereferenced in the
getcanonname_r plugin call, resulting in the use after free.
Fix this by copying h_name over and freeing it at the end. This
resolves BZ #30843, which is assigned CVE-2023-4806. This is a minimal
RHEL-8-specific fix. Test case differences from upstream:
- The test module needs to explicitly link against libnss_files on
RHEL-8; upstream libnss_files is built into libc.so.
- Test module code was adapted to not use the upstream NSS module
convenience macros.
This change is adapted from the following commit from upstream:
commit 973fe93a5675c42798b2161c6f29c01b0e243994
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Fri Sep 15 13:51:12 2023 -0400
getaddrinfo: Fix use after free in getcanonname (CVE-2023-4806)
When an NSS plugin only implements the _gethostbyname2_r and
_getcanonname_r callbacks, getaddrinfo could use memory that was freed
during tmpbuf resizing, through h_name in a previous query response.
The backing store for res->at->name when doing a query with
gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in
gethosts during the query. For AF_INET6 lookup with AI_ALL |
AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second
for a v4 lookup. In this case, if the first call reallocates tmpbuf
enough number of times, resulting in a malloc, th->h_name (that
res->at->name refers to) ends up on a heap allocated storage in tmpbuf.
Now if the second call to gethosts also causes the plugin callback to
return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF
reference in res->at->name. This then gets dereferenced in the
getcanonname_r plugin call, resulting in the use after free.
Fix this by copying h_name over and freeing it at the end. This
resolves BZ #30843, which is assigned CVE-2023-4806.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
diff --git a/nss/Makefile b/nss/Makefile
index cfb255c6e7a3a4de..5829a2539306ddb5 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -66,7 +66,8 @@ xtests = bug-erange
tests-container = \
tst-nss-db-endpwent \
tst-nss-db-endgrent \
- tst-nss-gai-actions
+ tst-nss-gai-actions \
+ tst-nss-gai-hv2-canonname
# Tests which need libdl
ifeq (yes,$(build-shared))
@@ -132,7 +133,8 @@ 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 nss_test_errno.os
+extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \
+ nss_test_gai_hv2_canonname.os
include ../Rules
@@ -169,12 +171,17 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver
libof-nss_test1 = extramodules
libof-nss_test2 = extramodules
libof-nss_test_errno = extramodules
+libof-nss_test_gai_hv2_canonname = extramodules
$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps)
$(build-module)
$(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps)
$(build-module)
$(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps)
$(build-module)
+$(objpfx)/libnss_test_gai_hv2_canonname.so: \
+ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps) \
+ $(objpfx)/libnss_files.so
+ $(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
@@ -187,10 +194,14 @@ endif
$(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \
$(objpfx)/libnss_test_errno.so
$(make-link)
+$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \
+ $(objpfx)/libnss_test_gai_hv2_canonname.so
+ $(make-link)
$(patsubst %,$(objpfx)%.out,$(tests)) : \
$(objpfx)/libnss_test1.so$(libnss_test1.so-version) \
$(objpfx)/libnss_test2.so$(libnss_test2.so-version) \
- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version)
+ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \
+ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version)
ifeq (yes,$(have-thread-library))
$(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c
new file mode 100644
index 0000000000000000..4195d7d24fdd5f6d
--- /dev/null
+++ b/nss/nss_test_gai_hv2_canonname.c
@@ -0,0 +1,64 @@
+/* NSS service provider that only provides gethostbyname2_r.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <netdb.h>
+#include <nss.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nss/tst-nss-gai-hv2-canonname.h"
+
+/* Catch misnamed and functions. */
+#pragma GCC diagnostic error "-Wmissing-prototypes"
+
+extern enum nss_status _nss_files_gethostbyname2_r (const char *, int,
+ struct hostent *, char *,
+ size_t, int *, int *);
+
+enum nss_status
+_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *, int, struct hostent
+ *, char *, size_t, int *, int *);
+
+enum nss_status
+_nss_test_gai_hv2_canonname_getcanonname_r (const char *, char *, size_t, char
+ **, int *, int *);
+
+enum nss_status
+_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af,
+ struct hostent *result,
+ char *buffer, size_t buflen,
+ int *errnop, int *herrnop)
+{
+ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop,
+ herrnop);
+}
+
+enum nss_status
+_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer,
+ size_t buflen, char **result,
+ int *errnop, int *h_errnop)
+{
+ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail
+ the test. */
+ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME))
+ || buflen < sizeof (QUERYNAME))
+ abort ();
+
+ strncpy (buffer, name, buflen);
+ *result = buffer;
+ return NSS_STATUS_SUCCESS;
+}
diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c
new file mode 100644
index 0000000000000000..d5f10c07d6a90773
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.c
@@ -0,0 +1,63 @@
+/* Test NSS query path for plugins that only implement gethostbyname2
+ (#30843).
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <nss.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include "nss/tst-nss-gai-hv2-canonname.h"
+
+#define PREPARE do_prepare
+
+static void do_prepare (int a, char **av)
+{
+ FILE *hosts = xfopen ("/etc/hosts", "w");
+ for (unsigned i = 2; i < 255; i++)
+ {
+ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i);
+ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i);
+ }
+ xfclose (hosts);
+}
+
+static int
+do_test (void)
+{
+ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname");
+
+ struct addrinfo hints = {};
+ struct addrinfo *result = NULL;
+
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME;
+
+ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result);
+
+ if (ret != 0)
+ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret));
+
+ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME);
+
+ freeaddrinfo(result);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h
new file mode 100644
index 0000000000000000..14f2a9cb0867dff9
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.h
@@ -0,0 +1 @@
+#define QUERYNAME "test.example.com"
diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req
new file mode 100644
index 0000000000000000..e69de29bb2d1d643
diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
new file mode 100644
index 0000000000000000..31848b4a28524af6
--- /dev/null
+++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script
@@ -0,0 +1,2 @@
+cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2
+su
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 4fa963644af8b7d5..46046504a6858f2e 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -233,7 +233,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
}
array[i].next = array + i + 1;
}
- array[0].name = h->h_name;
array[count - 1].next = NULL;
*result = array;
@@ -287,6 +286,18 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
} \
*pat = addrmem; \
\
+ /* Store h_name so that it survives accidental deallocation when \
+ gethosts is called again and tmpbuf gets reallocated. */ \
+ if (h_name == NULL && th.h_name != NULL) \
+ { \
+ h_name = __strdup (th.h_name); \
+ if (h_name == NULL) \
+ { \
+ __resolv_context_put (res_ctx); \
+ result = -EAI_SYSTEM; \
+ goto free_and_return; \
+ } \
+ } \
if (localcanon != NULL && canon == NULL) \
{ \
canonbuf = __strdup (localcanon); \
@@ -323,15 +334,15 @@ typedef enum nss_status (*nss_getcanonname_r)
memory allocation failure. The returned string is allocated on the
heap; the caller has to free it. */
static char *
-getcanonname (service_user *nip, struct gaih_addrtuple *at, const char *name)
+getcanonname (service_user *nip, const char *hname, const char *name)
{
nss_getcanonname_r cfct = __nss_lookup_function (nip, "getcanonname_r");
char *s = (char *) name;
if (cfct != NULL)
{
char buf[256];
- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf),
- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS)
+ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno,
+ &h_errno)) != NSS_STATUS_SUCCESS)
/* If the canonical name cannot be determined, use the passed
string. */
s = (char *) name;
@@ -349,6 +360,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
struct gaih_addrtuple *at = NULL;
bool got_ipv6 = false;
const char *canon = NULL;
+ char *h_name = NULL;
const char *orig_name = name;
/* Reserve stack memory for the scratch buffer in the getaddrinfo
@@ -919,7 +931,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if ((req->ai_flags & AI_CANONNAME) != 0
&& canon == NULL)
{
- canonbuf = getcanonname (nip, at, name);
+ canonbuf = getcanonname (nip, h_name, name);
if (canonbuf == NULL)
{
__resolv_context_enable_inet6
@@ -1169,6 +1181,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
free ((char *) name);
free (addrmem);
free (canonbuf);
+ free (h_name);
return result;
}

View File

@ -1,22 +0,0 @@
Work around in the test case, the fact that RHEL-8 NSS modules
infrastructure incorrectly allows merging in the hosts database. This
is a RHEL-8 only fix.
diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
index efca6cd1837a172a..c35e752896eceb2a 100644
--- a/nss/tst-nss-gai-actions.c
+++ b/nss/tst-nss-gai-actions.c
@@ -87,6 +87,13 @@ do_one_test (int action, int family, bool canon)
case ACTION_MERGE:
if (ret == 0)
{
+ if (hints.ai_flags == 0 && hints.ai_family == AF_INET)
+ {
+ printf ("***** RHEL-8 limitation: "
+ "NSS modules infrastructure incorrectly allows MERGE\n");
+ return;
+ }
+
char *formatted = support_format_addrinfo (ai, ret);
printf ("merge unexpectedly succeeded:\n %s\n", formatted);

View File

@ -1,979 +0,0 @@
commit 228cdb00a045ae3b68a91b35c7548bab6029446e
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Thu Mar 17 11:44:34 2022 +0530
Simplify allocations and fix merge and continue actions [BZ #28931]
Allocations for address tuples is currently a bit confusing because of
the pointer chasing through PAT, making it hard to observe the sequence
in which allocations have been made. Narrow scope of the pointer
chasing through PAT so that it is only used where necessary.
This also tightens actions behaviour with the hosts database in
getaddrinfo to comply with the manual text. The "continue" action
discards previous results and the "merge" action results in an immedate
lookup failure. Consequently, chaining of allocations across modules is
no longer necessary, thus opening up cleanup opportunities.
A test has been added that checks some combinations to ensure that they
work correctly.
Resolves: BZ #28931
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215)
Conflicts:
nss/Makefile
(Missing test cases)
sysdeps/posix/getaddrinfo.c
(RES_USE_INET6 still present in RHEL-8 and NSS module traversal rewrite
not in RHEL-8)
diff --git a/nss/Makefile b/nss/Makefile
index e8a7d9c7b3cefcdf..cfb255c6e7a3a4de 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -65,7 +65,8 @@ xtests = bug-erange
tests-container = \
tst-nss-db-endpwent \
- tst-nss-db-endgrent
+ tst-nss-db-endgrent \
+ tst-nss-gai-actions
# Tests which need libdl
ifeq (yes,$(build-shared))
diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
new file mode 100644
index 0000000000000000..efca6cd1837a172a
--- /dev/null
+++ b/nss/tst-nss-gai-actions.c
@@ -0,0 +1,149 @@
+/* Test continue and merge NSS actions for getaddrinfo.
+ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <nss.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <support/check.h>
+#include <support/format_nss.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+enum
+{
+ ACTION_MERGE = 0,
+ ACTION_CONTINUE,
+};
+
+static const char *
+family_str (int family)
+{
+ switch (family)
+ {
+ case AF_UNSPEC:
+ return "AF_UNSPEC";
+ case AF_INET:
+ return "AF_INET";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static const char *
+action_str (int action)
+{
+ switch (action)
+ {
+ case ACTION_MERGE:
+ return "merge";
+ case ACTION_CONTINUE:
+ return "continue";
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static void
+do_one_test (int action, int family, bool canon)
+{
+ struct addrinfo hints =
+ {
+ .ai_family = family,
+ };
+
+ struct addrinfo *ai;
+
+ if (canon)
+ hints.ai_flags = AI_CANONNAME;
+
+ printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
+ action_str (action), family_str (family),
+ canon ? "AI_CANONNAME" : "");
+
+ int ret = getaddrinfo ("example.org", "80", &hints, &ai);
+
+ switch (action)
+ {
+ case ACTION_MERGE:
+ if (ret == 0)
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ printf ("merge unexpectedly succeeded:\n %s\n", formatted);
+ support_record_failure ();
+ free (formatted);
+ }
+ else
+ return;
+ case ACTION_CONTINUE:
+ {
+ char *formatted = support_format_addrinfo (ai, ret);
+
+ /* Verify that the result appears exactly once. */
+ const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
+ "address: DGRAM/UDP 192.0.0.1 80\n"
+ "address: RAW/IP 192.0.0.1 80\n";
+
+ const char *contains = strstr (formatted, expected);
+ const char *contains2 = NULL;
+
+ if (contains != NULL)
+ contains2 = strstr (contains + strlen (expected), expected);
+
+ if (contains == NULL || contains2 != NULL)
+ {
+ printf ("continue failed:\n%s\n", formatted);
+ support_record_failure ();
+ }
+
+ free (formatted);
+ break;
+ }
+ default:
+ __builtin_unreachable ();
+ }
+}
+
+static void
+do_one_test_set (int action)
+{
+ char buf[32];
+
+ snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
+ action_str (action));
+ __nss_configure_lookup ("hosts", buf);
+
+ do_one_test (action, AF_UNSPEC, false);
+ do_one_test (action, AF_INET, false);
+ do_one_test (action, AF_INET, true);
+}
+
+static int
+do_test (void)
+{
+ do_one_test_set (ACTION_CONTINUE);
+ do_one_test_set (ACTION_MERGE);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf
new file mode 100644
index 0000000000000000..d1a59f73a90f2993
--- /dev/null
+++ b/nss/tst-nss-gai-actions.root/etc/host.conf
@@ -0,0 +1 @@
+multi on
diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts
new file mode 100644
index 0000000000000000..50ce9774dc2c21d9
--- /dev/null
+++ b/nss/tst-nss-gai-actions.root/etc/hosts
@@ -0,0 +1,508 @@
+192.0.0.1 example.org
+192.0.0.2 example.org
+192.0.0.3 example.org
+192.0.0.4 example.org
+192.0.0.5 example.org
+192.0.0.6 example.org
+192.0.0.7 example.org
+192.0.0.8 example.org
+192.0.0.9 example.org
+192.0.0.10 example.org
+192.0.0.11 example.org
+192.0.0.12 example.org
+192.0.0.13 example.org
+192.0.0.14 example.org
+192.0.0.15 example.org
+192.0.0.16 example.org
+192.0.0.17 example.org
+192.0.0.18 example.org
+192.0.0.19 example.org
+192.0.0.20 example.org
+192.0.0.21 example.org
+192.0.0.22 example.org
+192.0.0.23 example.org
+192.0.0.24 example.org
+192.0.0.25 example.org
+192.0.0.26 example.org
+192.0.0.27 example.org
+192.0.0.28 example.org
+192.0.0.29 example.org
+192.0.0.30 example.org
+192.0.0.31 example.org
+192.0.0.32 example.org
+192.0.0.33 example.org
+192.0.0.34 example.org
+192.0.0.35 example.org
+192.0.0.36 example.org
+192.0.0.37 example.org
+192.0.0.38 example.org
+192.0.0.39 example.org
+192.0.0.40 example.org
+192.0.0.41 example.org
+192.0.0.42 example.org
+192.0.0.43 example.org
+192.0.0.44 example.org
+192.0.0.45 example.org
+192.0.0.46 example.org
+192.0.0.47 example.org
+192.0.0.48 example.org
+192.0.0.49 example.org
+192.0.0.50 example.org
+192.0.0.51 example.org
+192.0.0.52 example.org
+192.0.0.53 example.org
+192.0.0.54 example.org
+192.0.0.55 example.org
+192.0.0.56 example.org
+192.0.0.57 example.org
+192.0.0.58 example.org
+192.0.0.59 example.org
+192.0.0.60 example.org
+192.0.0.61 example.org
+192.0.0.62 example.org
+192.0.0.63 example.org
+192.0.0.64 example.org
+192.0.0.65 example.org
+192.0.0.66 example.org
+192.0.0.67 example.org
+192.0.0.68 example.org
+192.0.0.69 example.org
+192.0.0.70 example.org
+192.0.0.71 example.org
+192.0.0.72 example.org
+192.0.0.73 example.org
+192.0.0.74 example.org
+192.0.0.75 example.org
+192.0.0.76 example.org
+192.0.0.77 example.org
+192.0.0.78 example.org
+192.0.0.79 example.org
+192.0.0.80 example.org
+192.0.0.81 example.org
+192.0.0.82 example.org
+192.0.0.83 example.org
+192.0.0.84 example.org
+192.0.0.85 example.org
+192.0.0.86 example.org
+192.0.0.87 example.org
+192.0.0.88 example.org
+192.0.0.89 example.org
+192.0.0.90 example.org
+192.0.0.91 example.org
+192.0.0.92 example.org
+192.0.0.93 example.org
+192.0.0.94 example.org
+192.0.0.95 example.org
+192.0.0.96 example.org
+192.0.0.97 example.org
+192.0.0.98 example.org
+192.0.0.99 example.org
+192.0.0.100 example.org
+192.0.0.101 example.org
+192.0.0.102 example.org
+192.0.0.103 example.org
+192.0.0.104 example.org
+192.0.0.105 example.org
+192.0.0.106 example.org
+192.0.0.107 example.org
+192.0.0.108 example.org
+192.0.0.109 example.org
+192.0.0.110 example.org
+192.0.0.111 example.org
+192.0.0.112 example.org
+192.0.0.113 example.org
+192.0.0.114 example.org
+192.0.0.115 example.org
+192.0.0.116 example.org
+192.0.0.117 example.org
+192.0.0.118 example.org
+192.0.0.119 example.org
+192.0.0.120 example.org
+192.0.0.121 example.org
+192.0.0.122 example.org
+192.0.0.123 example.org
+192.0.0.124 example.org
+192.0.0.125 example.org
+192.0.0.126 example.org
+192.0.0.127 example.org
+192.0.0.128 example.org
+192.0.0.129 example.org
+192.0.0.130 example.org
+192.0.0.131 example.org
+192.0.0.132 example.org
+192.0.0.133 example.org
+192.0.0.134 example.org
+192.0.0.135 example.org
+192.0.0.136 example.org
+192.0.0.137 example.org
+192.0.0.138 example.org
+192.0.0.139 example.org
+192.0.0.140 example.org
+192.0.0.141 example.org
+192.0.0.142 example.org
+192.0.0.143 example.org
+192.0.0.144 example.org
+192.0.0.145 example.org
+192.0.0.146 example.org
+192.0.0.147 example.org
+192.0.0.148 example.org
+192.0.0.149 example.org
+192.0.0.150 example.org
+192.0.0.151 example.org
+192.0.0.152 example.org
+192.0.0.153 example.org
+192.0.0.154 example.org
+192.0.0.155 example.org
+192.0.0.156 example.org
+192.0.0.157 example.org
+192.0.0.158 example.org
+192.0.0.159 example.org
+192.0.0.160 example.org
+192.0.0.161 example.org
+192.0.0.162 example.org
+192.0.0.163 example.org
+192.0.0.164 example.org
+192.0.0.165 example.org
+192.0.0.166 example.org
+192.0.0.167 example.org
+192.0.0.168 example.org
+192.0.0.169 example.org
+192.0.0.170 example.org
+192.0.0.171 example.org
+192.0.0.172 example.org
+192.0.0.173 example.org
+192.0.0.174 example.org
+192.0.0.175 example.org
+192.0.0.176 example.org
+192.0.0.177 example.org
+192.0.0.178 example.org
+192.0.0.179 example.org
+192.0.0.180 example.org
+192.0.0.181 example.org
+192.0.0.182 example.org
+192.0.0.183 example.org
+192.0.0.184 example.org
+192.0.0.185 example.org
+192.0.0.186 example.org
+192.0.0.187 example.org
+192.0.0.188 example.org
+192.0.0.189 example.org
+192.0.0.190 example.org
+192.0.0.191 example.org
+192.0.0.192 example.org
+192.0.0.193 example.org
+192.0.0.194 example.org
+192.0.0.195 example.org
+192.0.0.196 example.org
+192.0.0.197 example.org
+192.0.0.198 example.org
+192.0.0.199 example.org
+192.0.0.200 example.org
+192.0.0.201 example.org
+192.0.0.202 example.org
+192.0.0.203 example.org
+192.0.0.204 example.org
+192.0.0.205 example.org
+192.0.0.206 example.org
+192.0.0.207 example.org
+192.0.0.208 example.org
+192.0.0.209 example.org
+192.0.0.210 example.org
+192.0.0.211 example.org
+192.0.0.212 example.org
+192.0.0.213 example.org
+192.0.0.214 example.org
+192.0.0.215 example.org
+192.0.0.216 example.org
+192.0.0.217 example.org
+192.0.0.218 example.org
+192.0.0.219 example.org
+192.0.0.220 example.org
+192.0.0.221 example.org
+192.0.0.222 example.org
+192.0.0.223 example.org
+192.0.0.224 example.org
+192.0.0.225 example.org
+192.0.0.226 example.org
+192.0.0.227 example.org
+192.0.0.228 example.org
+192.0.0.229 example.org
+192.0.0.230 example.org
+192.0.0.231 example.org
+192.0.0.232 example.org
+192.0.0.233 example.org
+192.0.0.234 example.org
+192.0.0.235 example.org
+192.0.0.236 example.org
+192.0.0.237 example.org
+192.0.0.238 example.org
+192.0.0.239 example.org
+192.0.0.240 example.org
+192.0.0.241 example.org
+192.0.0.242 example.org
+192.0.0.243 example.org
+192.0.0.244 example.org
+192.0.0.245 example.org
+192.0.0.246 example.org
+192.0.0.247 example.org
+192.0.0.248 example.org
+192.0.0.249 example.org
+192.0.0.250 example.org
+192.0.0.251 example.org
+192.0.0.252 example.org
+192.0.0.253 example.org
+192.0.0.254 example.org
+192.0.1.1 example.org
+192.0.1.2 example.org
+192.0.1.3 example.org
+192.0.1.4 example.org
+192.0.1.5 example.org
+192.0.1.6 example.org
+192.0.1.7 example.org
+192.0.1.8 example.org
+192.0.1.9 example.org
+192.0.1.10 example.org
+192.0.1.11 example.org
+192.0.1.12 example.org
+192.0.1.13 example.org
+192.0.1.14 example.org
+192.0.1.15 example.org
+192.0.1.16 example.org
+192.0.1.17 example.org
+192.0.1.18 example.org
+192.0.1.19 example.org
+192.0.1.20 example.org
+192.0.1.21 example.org
+192.0.1.22 example.org
+192.0.1.23 example.org
+192.0.1.24 example.org
+192.0.1.25 example.org
+192.0.1.26 example.org
+192.0.1.27 example.org
+192.0.1.28 example.org
+192.0.1.29 example.org
+192.0.1.30 example.org
+192.0.1.31 example.org
+192.0.1.32 example.org
+192.0.1.33 example.org
+192.0.1.34 example.org
+192.0.1.35 example.org
+192.0.1.36 example.org
+192.0.1.37 example.org
+192.0.1.38 example.org
+192.0.1.39 example.org
+192.0.1.40 example.org
+192.0.1.41 example.org
+192.0.1.42 example.org
+192.0.1.43 example.org
+192.0.1.44 example.org
+192.0.1.45 example.org
+192.0.1.46 example.org
+192.0.1.47 example.org
+192.0.1.48 example.org
+192.0.1.49 example.org
+192.0.1.50 example.org
+192.0.1.51 example.org
+192.0.1.52 example.org
+192.0.1.53 example.org
+192.0.1.54 example.org
+192.0.1.55 example.org
+192.0.1.56 example.org
+192.0.1.57 example.org
+192.0.1.58 example.org
+192.0.1.59 example.org
+192.0.1.60 example.org
+192.0.1.61 example.org
+192.0.1.62 example.org
+192.0.1.63 example.org
+192.0.1.64 example.org
+192.0.1.65 example.org
+192.0.1.66 example.org
+192.0.1.67 example.org
+192.0.1.68 example.org
+192.0.1.69 example.org
+192.0.1.70 example.org
+192.0.1.71 example.org
+192.0.1.72 example.org
+192.0.1.73 example.org
+192.0.1.74 example.org
+192.0.1.75 example.org
+192.0.1.76 example.org
+192.0.1.77 example.org
+192.0.1.78 example.org
+192.0.1.79 example.org
+192.0.1.80 example.org
+192.0.1.81 example.org
+192.0.1.82 example.org
+192.0.1.83 example.org
+192.0.1.84 example.org
+192.0.1.85 example.org
+192.0.1.86 example.org
+192.0.1.87 example.org
+192.0.1.88 example.org
+192.0.1.89 example.org
+192.0.1.90 example.org
+192.0.1.91 example.org
+192.0.1.92 example.org
+192.0.1.93 example.org
+192.0.1.94 example.org
+192.0.1.95 example.org
+192.0.1.96 example.org
+192.0.1.97 example.org
+192.0.1.98 example.org
+192.0.1.99 example.org
+192.0.1.100 example.org
+192.0.1.101 example.org
+192.0.1.102 example.org
+192.0.1.103 example.org
+192.0.1.104 example.org
+192.0.1.105 example.org
+192.0.1.106 example.org
+192.0.1.107 example.org
+192.0.1.108 example.org
+192.0.1.109 example.org
+192.0.1.110 example.org
+192.0.1.111 example.org
+192.0.1.112 example.org
+192.0.1.113 example.org
+192.0.1.114 example.org
+192.0.1.115 example.org
+192.0.1.116 example.org
+192.0.1.117 example.org
+192.0.1.118 example.org
+192.0.1.119 example.org
+192.0.1.120 example.org
+192.0.1.121 example.org
+192.0.1.122 example.org
+192.0.1.123 example.org
+192.0.1.124 example.org
+192.0.1.125 example.org
+192.0.1.126 example.org
+192.0.1.127 example.org
+192.0.1.128 example.org
+192.0.1.129 example.org
+192.0.1.130 example.org
+192.0.1.131 example.org
+192.0.1.132 example.org
+192.0.1.133 example.org
+192.0.1.134 example.org
+192.0.1.135 example.org
+192.0.1.136 example.org
+192.0.1.137 example.org
+192.0.1.138 example.org
+192.0.1.139 example.org
+192.0.1.140 example.org
+192.0.1.141 example.org
+192.0.1.142 example.org
+192.0.1.143 example.org
+192.0.1.144 example.org
+192.0.1.145 example.org
+192.0.1.146 example.org
+192.0.1.147 example.org
+192.0.1.148 example.org
+192.0.1.149 example.org
+192.0.1.150 example.org
+192.0.1.151 example.org
+192.0.1.152 example.org
+192.0.1.153 example.org
+192.0.1.154 example.org
+192.0.1.155 example.org
+192.0.1.156 example.org
+192.0.1.157 example.org
+192.0.1.158 example.org
+192.0.1.159 example.org
+192.0.1.160 example.org
+192.0.1.161 example.org
+192.0.1.162 example.org
+192.0.1.163 example.org
+192.0.1.164 example.org
+192.0.1.165 example.org
+192.0.1.166 example.org
+192.0.1.167 example.org
+192.0.1.168 example.org
+192.0.1.169 example.org
+192.0.1.170 example.org
+192.0.1.171 example.org
+192.0.1.172 example.org
+192.0.1.173 example.org
+192.0.1.174 example.org
+192.0.1.175 example.org
+192.0.1.176 example.org
+192.0.1.177 example.org
+192.0.1.178 example.org
+192.0.1.179 example.org
+192.0.1.180 example.org
+192.0.1.181 example.org
+192.0.1.182 example.org
+192.0.1.183 example.org
+192.0.1.184 example.org
+192.0.1.185 example.org
+192.0.1.186 example.org
+192.0.1.187 example.org
+192.0.1.188 example.org
+192.0.1.189 example.org
+192.0.1.190 example.org
+192.0.1.191 example.org
+192.0.1.192 example.org
+192.0.1.193 example.org
+192.0.1.194 example.org
+192.0.1.195 example.org
+192.0.1.196 example.org
+192.0.1.197 example.org
+192.0.1.198 example.org
+192.0.1.199 example.org
+192.0.1.200 example.org
+192.0.1.201 example.org
+192.0.1.202 example.org
+192.0.1.203 example.org
+192.0.1.204 example.org
+192.0.1.205 example.org
+192.0.1.206 example.org
+192.0.1.207 example.org
+192.0.1.208 example.org
+192.0.1.209 example.org
+192.0.1.210 example.org
+192.0.1.211 example.org
+192.0.1.212 example.org
+192.0.1.213 example.org
+192.0.1.214 example.org
+192.0.1.215 example.org
+192.0.1.216 example.org
+192.0.1.217 example.org
+192.0.1.218 example.org
+192.0.1.219 example.org
+192.0.1.220 example.org
+192.0.1.221 example.org
+192.0.1.222 example.org
+192.0.1.223 example.org
+192.0.1.224 example.org
+192.0.1.225 example.org
+192.0.1.226 example.org
+192.0.1.227 example.org
+192.0.1.228 example.org
+192.0.1.229 example.org
+192.0.1.230 example.org
+192.0.1.231 example.org
+192.0.1.232 example.org
+192.0.1.233 example.org
+192.0.1.234 example.org
+192.0.1.235 example.org
+192.0.1.236 example.org
+192.0.1.237 example.org
+192.0.1.238 example.org
+192.0.1.239 example.org
+192.0.1.240 example.org
+192.0.1.241 example.org
+192.0.1.242 example.org
+192.0.1.243 example.org
+192.0.1.244 example.org
+192.0.1.245 example.org
+192.0.1.246 example.org
+192.0.1.247 example.org
+192.0.1.248 example.org
+192.0.1.249 example.org
+192.0.1.250 example.org
+192.0.1.251 example.org
+192.0.1.252 example.org
+192.0.1.253 example.org
+192.0.1.254 example.org
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index fae3dea81f19dba6..4fa963644af8b7d5 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -474,11 +474,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (name != NULL)
{
- at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
- at->family = AF_UNSPEC;
- at->scopeid = 0;
- at->next = NULL;
-
if (req->ai_flags & AI_IDN)
{
char *out;
@@ -489,13 +484,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
malloc_name = true;
}
- if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
+ uint32_t addr[4];
+ if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
{
+ at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
- at->family = AF_INET;
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET;
+ }
else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
{
- at->addr[3] = at->addr[0];
+ at->addr[3] = addr[0];
at->addr[2] = htonl (0xffff);
at->addr[1] = 0;
at->addr[0] = 0;
@@ -509,49 +512,62 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (req->ai_flags & AI_CANONNAME)
canon = name;
+
+ goto process_list;
}
- else if (at->family == AF_UNSPEC)
+
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+ int e;
+
+ if (scope_delim == NULL)
+ e = inet_pton (AF_INET6, name, addr);
+ else
+ e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
+
+ if (e > 0)
{
- char *scope_delim = strchr (name, SCOPE_DELIMITER);
- int e;
- if (scope_delim == NULL)
- e = inet_pton (AF_INET6, name, at->addr);
+ at = alloca_account (sizeof (struct gaih_addrtuple),
+ alloca_used);
+ at->scopeid = 0;
+ at->next = NULL;
+
+ if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+ {
+ memcpy (at->addr, addr, sizeof (at->addr));
+ at->family = AF_INET6;
+ }
+ else if (req->ai_family == AF_INET
+ && IN6_IS_ADDR_V4MAPPED (addr))
+ {
+ at->addr[0] = addr[3];
+ at->addr[1] = addr[1];
+ at->addr[2] = addr[2];
+ at->addr[3] = addr[3];
+ at->family = AF_INET;
+ }
else
- e = __inet_pton_length (AF_INET6, name, scope_delim - name,
- at->addr);
- if (e > 0)
{
- if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
- at->family = AF_INET6;
- else if (req->ai_family == AF_INET
- && IN6_IS_ADDR_V4MAPPED (at->addr))
- {
- at->addr[0] = at->addr[3];
- at->family = AF_INET;
- }
- else
- {
- result = -EAI_ADDRFAMILY;
- goto free_and_return;
- }
-
- if (scope_delim != NULL
- && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
- scope_delim + 1,
- &at->scopeid) != 0)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ result = -EAI_ADDRFAMILY;
+ goto free_and_return;
+ }
- if (req->ai_flags & AI_CANONNAME)
- canon = name;
+ if (scope_delim != NULL
+ && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
+ scope_delim + 1,
+ &at->scopeid) != 0)
+ {
+ result = -EAI_NONAME;
+ goto free_and_return;
}
+
+ if (req->ai_flags & AI_CANONNAME)
+ canon = name;
+
+ goto process_list;
}
- if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
+ if ((req->ai_flags & AI_NUMERICHOST) == 0)
{
- struct gaih_addrtuple **pat = &at;
int no_data = 0;
int no_inet6_data = 0;
service_user *nip;
@@ -560,6 +576,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
int no_more;
struct resolv_context *res_ctx = NULL;
bool res_enable_inet6 = false;
+ bool do_merge = false;
/* If we do not have to look for IPv6 addresses or the canonical
name, use the simple, old functions, which do not support
@@ -596,7 +613,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
result = -EAI_MEMORY;
goto free_and_return;
}
- *pat = addrmem;
+ at = addrmem;
}
else
{
@@ -649,6 +666,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
struct gaih_addrtuple *addrfree = addrmem;
+ struct gaih_addrtuple **pat = &at;
+
for (int i = 0; i < air->naddrs; ++i)
{
socklen_t size = (air->family[i] == AF_INET
@@ -712,12 +731,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
free (air);
- if (at->family == AF_UNSPEC)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
-
goto process_list;
}
else if (err == 0)
@@ -756,6 +769,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more)
{
+ /* Always start afresh; continue should discard previous results
+ and the hosts database does not support merge. */
+ at = NULL;
+ free (canonbuf);
+ free (addrmem);
+ canon = canonbuf = NULL;
+ addrmem = NULL;
+ got_ipv6 = false;
+
+ if (do_merge)
+ {
+ __set_h_errno (NETDB_INTERNAL);
+ __set_errno (EBUSY);
+ break;
+ }
+
no_data = 0;
nss_gethostbyname4_r fct4 = NULL;
@@ -768,12 +797,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
while (1)
{
- status = DL_CALL_FCT (fct4, (name, pat,
+ status = DL_CALL_FCT (fct4, (name, &at,
tmpbuf->data, tmpbuf->length,
&errno, &h_errno,
NULL));
if (status == NSS_STATUS_SUCCESS)
break;
+ /* gethostbyname4_r may write into AT, so reset it. */
+ at = NULL;
if (status != NSS_STATUS_TRYAGAIN
|| errno != ERANGE || h_errno != NETDB_INTERNAL)
{
@@ -800,7 +831,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
no_data = 1;
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
- canon = (*pat)->name;
+ canon = at->name;
+
+ struct gaih_addrtuple **pat = &at;
while (*pat != NULL)
{
@@ -852,6 +885,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (fct != NULL)
{
+ struct gaih_addrtuple **pat = &at;
+
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
@@ -927,6 +962,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
+ /* The hosts database does not support MERGE. */
+ if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
+ do_merge = true;
+
if (nip->next == NULL)
no_more = -1;
else
@@ -960,7 +999,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
process_list:
- if (at->family == AF_UNSPEC)
+ if (at == NULL)
{
result = -EAI_NONAME;
goto free_and_return;

View File

@ -1,157 +0,0 @@
This patch was developed under embargo and cannot reference an upstream
commit. To find the associated commit please review the upstream git
log for CVE-2023-4911 to identify the relevant commits.
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue Sep 19 18:39:32 2023 -0400
tunables: Terminate if end of input is reached (CVE-2023-4911)
The string parsing routine may end up writing beyond bounds of tunestr
if the input tunable string is malformed, of the form name=name=val.
This gets processed twice, first as name=name=val and next as name=val,
resulting in tunestr being name=name=val:name=val, thus overflowing
tunestr.
Terminate the parsing loop at the first instance itself so that tunestr
does not overflow.
This also fixes up tst-env-setuid-tunables to actually handle failures
correct and add new tests to validate the fix for this CVE.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
NEWS
(Dropped)
elf/tst-env-setuid-tunables.c
(Trivial conflict at HAVE_TUNABLES)
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index 3c84809d44381241..2c878e08ea197b29 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -193,11 +193,7 @@ parse_tunables (char *tunestr, char *valstring)
/* If we reach the end of the string before getting a valid name-value
pair, bail out. */
if (p[len] == '\0')
- {
- if (__libc_enable_secure)
- tunestr[off] = '\0';
- return;
- }
+ break;
/* We did not find a valid name-value pair before encountering the
colon. */
@@ -257,9 +253,16 @@ parse_tunables (char *tunestr, char *valstring)
}
}
- if (p[len] != '\0')
- p += len + 1;
+ /* We reached the end while processing the tunable string. */
+ if (p[len] == '\0')
+ break;
+
+ p += len + 1;
}
+
+ /* Terminate tunestr before we leave. */
+ if (__libc_enable_secure)
+ tunestr[off] = '\0';
}
#endif
diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c
index 0b9b075c40598c6f..8b0861c4ad853040 100644
--- a/elf/tst-env-setuid-tunables.c
+++ b/elf/tst-env-setuid-tunables.c
@@ -52,6 +52,8 @@ const char *teststrings[] =
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.check=2",
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
":glibc.malloc.garbage=2:glibc.malloc.check=1",
@@ -70,6 +72,8 @@ const char *resultstrings[] =
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
+ "",
"",
"",
"",
@@ -84,11 +88,18 @@ test_child (int off)
const char *val = getenv ("GLIBC_TUNABLES");
#if HAVE_TUNABLES
+ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val);
+ fflush (stdout);
if (val != NULL && strcmp (val, resultstrings[off]) == 0)
return 0;
if (val != NULL)
- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
+ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n",
+ off, val, resultstrings[off]);
+ else
+ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off);
+
+ fflush (stdout);
return 1;
#else
@@ -117,21 +128,26 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
- exit (EXIT_SUCCESS);
+ /* Special return code to make sure that the child executed all the way
+ through. */
+ exit (42);
}
else
{
- int ret = 0;
-
/* Spawn tests. */
for (int i = 0; i < array_length (teststrings); i++)
{
char buf[INT_BUFSIZE_BOUND (int)];
- printf ("Spawned test for %s (%d)\n", teststrings[i], i);
+ printf ("[%d] Spawned test for %s\n", i, teststrings[i]);
snprintf (buf, sizeof (buf), "%d\n", i);
+ fflush (stdout);
if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
- exit (1);
+ {
+ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i);
+ support_record_failure ();
+ continue;
+ }
int status = support_capture_subprogram_self_sgid (buf);
@@ -139,9 +155,14 @@ do_test (int argc, char **argv)
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
- ret |= status;
+ if (WEXITSTATUS (status) != 42)
+ {
+ printf (" [%d] child failed with status %d\n", i,
+ WEXITSTATUS (status));
+ support_record_failure ();
+ }
}
- return ret;
+ return 0;
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,79 +0,0 @@
commit dbb75513f5cf9285c77c9e55777c5c35b653f890
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Sep 6 07:38:10 2022 +0200
elf: Rename _dl_sort_maps parameter from skip to force_first
The new implementation will not be able to skip an arbitrary number
of objects.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
index 99354dc08a010dd3..7a586749adc3fa7d 100644
--- a/elf/dl-sort-maps.c
+++ b/elf/dl-sort-maps.c
@@ -27,12 +27,12 @@
If FOR_FINI is true, this is called for finishing an object. */
static void
_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
- unsigned int skip, bool for_fini)
+ bool force_first, bool for_fini)
{
/* Allows caller to do the common optimization of skipping the first map,
usually the main binary. */
- maps += skip;
- nmaps -= skip;
+ maps += force_first;
+ nmaps -= force_first;
/* A list of one element need not be sorted. */
if (nmaps <= 1)
@@ -182,7 +182,7 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
static void
_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
- unsigned int skip __attribute__ ((unused)), bool for_fini)
+ bool force_first __attribute__ ((unused)), bool for_fini)
{
for (int i = nmaps - 1; i >= 0; i--)
maps[i]->l_visited = 0;
@@ -286,7 +286,7 @@ _dl_sort_maps_init (void)
void
_dl_sort_maps (struct link_map **maps, unsigned int nmaps,
- unsigned int skip, bool for_fini)
+ bool force_first, bool for_fini)
{
/* It can be tempting to use a static function pointer to store and call
the current selected sorting algorithm routine, but experimentation
@@ -296,9 +296,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
input cases. A simple if-case with direct function calls appears to
be the fastest. */
if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
- _dl_sort_maps_original (maps, nmaps, skip, for_fini);
+ _dl_sort_maps_original (maps, nmaps, force_first, for_fini);
else
- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
+ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini);
}
#endif /* HAVE_TUNABLES. */
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 9f09a4a280396659..2c1b4c47c6a6c643 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -1056,9 +1056,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
initializer functions have completed. */
extern void _dl_fini (void) attribute_hidden;
-/* Sort array MAPS according to dependencies of the contained objects. */
+/* Sort array MAPS according to dependencies of the contained objects.
+ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies
+ say otherwise. */
extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
- unsigned int skip, bool for_fini) attribute_hidden;
+ bool force_first, bool for_fini) attribute_hidden;
/* The dynamic linker calls this function before and having changing
any shared object mappings. The `r_state' member of `struct r_debug'

View File

@ -1,90 +0,0 @@
commit 1df71d32fe5f5905ffd5d100e5e9ca8ad6210891
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Sep 20 11:00:42 2022 +0200
elf: Implement force_first handling in _dl_sort_maps_dfs (bug 28937)
The implementation in _dl_close_worker requires that the first
element of l_initfini is always this very map (“We are always the
zeroth entry, and since we don't include ourselves in the
dependency analysis start at 1.”). Rather than fixing that
assumption, this commit adds an implementation of the force_first
argument to the new dependency sorting algorithm. This also means
that the directly dlopen'ed shared object is always initialized last,
which is the least surprising behavior in the presence of cycles.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
index 7a586749adc3fa7d..6f5c17b47b98fbc7 100644
--- a/elf/dl-sort-maps.c
+++ b/elf/dl-sort-maps.c
@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map,
static void
_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
- bool force_first __attribute__ ((unused)), bool for_fini)
+ bool force_first, bool for_fini)
{
+ struct link_map *first_map = maps[0];
for (int i = nmaps - 1; i >= 0; i--)
maps[i]->l_visited = 0;
@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
Adjusting the order so that maps[0] is last traversed naturally avoids
this problem.
- Further, the old "optimization" of skipping the main object at maps[0]
- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
- no longer valid, since traversing along object dependency-links
- may "find" the main object even when it is not included in the initial
- order (e.g. a dlopen()'ed shared object can have circular dependencies
- linked back to itself). In such a case, traversing N-1 objects will
- create a N-object result, and raise problems.
-
To summarize, just passing in the full list, and iterating from back
to front makes things much more straightforward. */
@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
}
memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
+
+ /* Skipping the first object at maps[0] is not valid in general,
+ since traversing along object dependency-links may "find" that
+ first object even when it is not included in the initial order
+ (e.g., a dlopen'ed shared object can have circular dependencies
+ linked back to itself). In such a case, traversing N-1 objects
+ will create a N-object result, and raise problems. Instead,
+ force the object back into first place after sorting. This naive
+ approach may introduce further dependency ordering violations
+ compared to rotating the cycle until the first map is again in
+ the first position, but as there is a cycle, at least one
+ violation is already present. */
+ if (force_first && maps[0] != first_map)
+ {
+ int i;
+ for (i = 0; maps[i] != first_map; ++i)
+ ;
+ assert (i < nmaps);
+ memmove (&maps[1], maps, i * sizeof (maps[0]));
+ maps[0] = first_map;
+ }
}
void
diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
index 5f7f18ef270bc12d..4bf9052db16fb352 100644
--- a/elf/dso-sort-tests-1.def
+++ b/elf/dso-sort-tests-1.def
@@ -64,3 +64,10 @@ output: b>a>{}<a<b
tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c
output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
+
+# Test that even in the presence of dependency loops involving dlopen'ed
+# object, that object is initialized last (and not unloaded prematurely).
+# Final destructor order is indeterminate due to the cycle.
+tst-bz28937: {+a;+b;-b;+c;%c};a->a1;a->a2;a2->a;b->b1;c->a1;c=>a1
+output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
+output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1

View File

@ -1,35 +0,0 @@
Downstream-specific patch to link DSO sorting tests with -ldl
if needed. Upstream does not need this because <dlfcn.h> interfaces
are part of libc.
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
index 43b5ec4d920ad6a3..ae85e0f4a6ae5b3e 100644
--- a/scripts/dso-ordering-test.py
+++ b/scripts/dso-ordering-test.py
@@ -657,6 +657,8 @@ def process_testcase(t):
% (test_name + "-" + dep + ".FAKE.so",
("$(objpfx)" + test_subdir + "/"
+ test_name + "-" + dep + ".so")))
+ makefile.write(
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % dso)
rule = ("$(objpfx)" + test_subdir + "/"
+ test_name + "-" + dep + ".FAKE.os: "
"$(objpfx)" + test_srcdir
@@ -685,6 +687,8 @@ def process_testcase(t):
+ test_descr.soname_map[o] + ".so")
ldflags += (" -Wl,-soname=" + soname)
makefile.write("LDFLAGS-%s = %s\n" % (dso, ldflags))
+ makefile.write(
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % dso)
if o in test_descr.callrefs:
makefile.write("%s-no-z-defs = yes\n" % (dso))
@@ -702,6 +706,8 @@ def process_testcase(t):
+ test_descr.soname_map['#'] + ".so")
ldflags += (" -Wl,-soname=" + soname)
makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags))
+ makefile.write(
+ "LDLIBS-%s += -Wl,--as-needed -ldl -Wl,--no-as-needed\n" % test_name)
rule = ("$(objpfx)" + test_subdir + "/" + test_name + ".o: "
"$(objpfx)" + test_srcdir + test_name + ".c\n"
"\t$(compile.c) $(OUTPUT_OPTION)\n")

View File

@ -1,189 +0,0 @@
commit b4bbedb1e75737a80bcc3d53d6eef1fbe0b5f4d5
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Sat Nov 6 14:13:27 2021 -0700
dso-ordering-test.py: Put all sources in one directory [BZ #28550]
Put all sources for DSO sorting tests in the dso-sort-tests-src directory
and compile test relocatable objects with
$(objpfx)tst-dso-ordering1-dir/tst-dso-ordering1-a.os: $(objpfx)dso-sort-tests-src/tst-dso-ordering1-a.c
$(compile.c) $(OUTPUT_OPTION)
to avoid random $< values from $(before-compile) when compiling test
relocatable objects with
$(objpfx)%$o: $(objpfx)%.c $(before-compile); $$(compile-command.c)
compile-command.c = $(compile.c) $(OUTPUT_OPTION) $(compile-mkdep-flags)
compile.c = $(CC) $< -c $(CFLAGS) $(CPPFLAGS)
for 3 "make -j 28" parallel builds on a machine with 112 cores at the
same time.
This partially fixes BZ #28550.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
index 944ee740527d60fd..bde0406be9da14fc 100644
--- a/scripts/dso-ordering-test.py
+++ b/scripts/dso-ordering-test.py
@@ -526,9 +526,13 @@ def process_testcase(t):
base_test_name = t.test_name
test_subdir = base_test_name + "-dir"
testpfx = objpfx + test_subdir + "/"
+ test_srcdir = "dso-sort-tests-src/"
+ testpfx_src = objpfx + test_srcdir
if not os.path.exists(testpfx):
os.mkdir(testpfx)
+ if not os.path.exists(testpfx_src):
+ os.mkdir(testpfx_src)
def find_objs_not_depended_on(t):
objs_not_depended_on = []
@@ -595,6 +599,11 @@ def process_testcase(t):
# Print out needed Makefile fragments for use in glibc/elf/Makefile.
module_names = ""
for o in test_descr.objs:
+ rule = ("$(objpfx)" + test_subdir + "/" + test_name
+ + "-" + o + ".os: $(objpfx)" + test_srcdir
+ + test_name + "-" + o + ".c\n"
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
+ makefile.write (rule)
module_names += " " + test_subdir + "/" + test_name + "-" + o
makefile.write("modules-names +=%s\n" % (module_names))
@@ -637,7 +646,7 @@ def process_testcase(t):
# object. This only needs to be done at most once for
# an object name.
if not dep in fake_created:
- f = open(testpfx + test_name + "-" + dep
+ f = open(testpfx_src + test_name + "-" + dep
+ ".FAKE.c", "w")
f.write(" \n")
f.close()
@@ -648,6 +657,12 @@ def process_testcase(t):
% (test_name + "-" + dep + ".FAKE.so",
("$(objpfx)" + test_subdir + "/"
+ test_name + "-" + dep + ".so")))
+ rule = ("$(objpfx)" + test_subdir + "/"
+ + test_name + "-" + dep + ".FAKE.os: "
+ "$(objpfx)" + test_srcdir
+ + test_name + "-" + dep + ".FAKE.c\n"
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
+ makefile.write (rule)
makefile.write \
("modules-names += %s\n"
% (test_subdir + "/"
@@ -687,6 +702,10 @@ def process_testcase(t):
+ test_descr.soname_map['#'] + ".so")
ldflags += (" -Wl,-soname=" + soname)
makefile.write("LDFLAGS-%s = %s\n" % (test_name, ldflags))
+ rule = ("$(objpfx)" + test_subdir + "/" + test_name + ".o: "
+ "$(objpfx)" + test_srcdir + test_name + ".c\n"
+ "\t$(compile.c) $(OUTPUT_OPTION)\n")
+ makefile.write (rule)
not_depended_objs = find_objs_not_depended_on(test_descr)
if not_depended_objs:
@@ -745,7 +764,7 @@ def process_testcase(t):
" something_failed=true\n"
"else\n"
" diff -wu ${common_objpfx}elf/%s/%s%s.output \\\n"
- " ${common_objpfx}elf/%s/%s%s.exp\n"
+ " ${common_objpfx}elf/%s%s%s.exp\n"
" if [ $? -ne 0 ]; then\n"
" echo '%sFAIL: %s%s expected output comparison'\n"
" something_failed=true\n"
@@ -753,14 +772,14 @@ def process_testcase(t):
"fi\n"
% (("X" if xfail else ""), test_name, tunable_descr,
test_subdir, test_name, tunable_sfx,
- test_subdir, base_test_name, exp_tunable_sfx,
+ test_srcdir, base_test_name, exp_tunable_sfx,
("X" if xfail else ""), test_name, tunable_descr))
# Generate C files according to dependency and calling relations from
# description string.
for obj in test_descr.objs:
src_name = test_name + "-" + obj + ".c"
- f = open(testpfx + src_name, "w")
+ f = open(testpfx_src + src_name, "w")
if obj in test_descr.callrefs:
called_objs = test_descr.callrefs[obj]
for callee in called_objs:
@@ -804,7 +823,7 @@ def process_testcase(t):
f.close()
# Open C file for writing main program
- f = open(testpfx + test_name + ".c", "w")
+ f = open(testpfx_src + test_name + ".c", "w")
# if there are some operations in main(), it means we need -ldl
f.write("#include <stdio.h>\n")
@@ -885,7 +904,7 @@ def process_testcase(t):
for obj in test_descr.objs:
src_name = test_name + "-" + obj + ".c"
obj_name = test_name + "-" + obj + ".os"
- run_cmd([build_gcc, "-c", "-fPIC", testpfx + src_name,
+ run_cmd([build_gcc, "-c", "-fPIC", testpfx_src + src_name,
"-o", testpfx + obj_name])
obj_processed = {}
@@ -903,10 +922,12 @@ def process_testcase(t):
deps.append(dep + ".FAKE")
if not dep in fake_created:
base_name = testpfx + test_name + "-" + dep
+ src_base_name = (testpfx_src + test_name
+ + "-" + dep)
cmd = [build_gcc, "-Wl,--no-as-needed",
("-Wl,-soname=" + base_name + ".so"),
"-shared", base_name + ".FAKE.c",
- "-o", base_name + ".FAKE.so"]
+ "-o", src_base_name + ".FAKE.so"]
run_cmd(cmd)
fake_created[dep] = True
dso_deps = map(lambda d: testpfx + test_name + "-" + d + ".so",
@@ -932,7 +953,7 @@ def process_testcase(t):
main_deps = map(lambda d: testpfx + test_name + "-" + d + ".so",
deps)
cmd = [build_gcc, "-Wl,--no-as-needed", "-o", testpfx + test_name,
- testpfx + test_name + ".c", "-L%s" % (os.getcwd()),
+ testpfx_src + test_name + ".c", "-L%s" % (os.getcwd()),
"-Wl,-rpath-link=%s" % (os.getcwd())]
if '#' in test_descr.soname_map:
soname = ("-Wl,-soname=" + testpfx + test_name + "-"
@@ -987,14 +1008,14 @@ def process_testcase(t):
sfx = ""
if r[0] != "":
sfx = "-" + r[0].replace("=","_")
- f = open(testpfx + t.test_name + sfx + ".exp", "w")
+ f = open(testpfx_src + t.test_name + sfx + ".exp", "w")
(output, xfail) = r[1]
f.write('%s' % output)
f.close()
# Create header part of top-level testcase shell script, to wrap execution
# and output comparison together.
- t.sh = open(testpfx + t.test_name + ".sh", "w")
+ t.sh = open(testpfx_src + t.test_name + ".sh", "w")
t.sh.write("#!/bin/sh\n")
t.sh.write("# Test driver for %s, generated by "
"dso-ordering-test.py\n" % (t.test_name))
@@ -1022,12 +1043,12 @@ def process_testcase(t):
sfx = ""
if r[0] != "":
sfx = "-" + r[0].replace("=","_")
- expected_output_files += " $(objpfx)%s/%s%s.exp" % (test_subdir,
+ expected_output_files += " $(objpfx)%s%s%s.exp" % (test_srcdir,
t.test_name, sfx)
makefile.write \
- ("$(objpfx)%s.out: $(objpfx)%s/%s.sh%s "
+ ("$(objpfx)%s.out: $(objpfx)%s%s.sh%s "
"$(common-objpfx)support/test-run-command\n"
- % (t.test_name, test_subdir, t.test_name,
+ % (t.test_name, test_srcdir, t.test_name,
expected_output_files))
makefile.write("\t$(SHELL) $< $(common-objpfx) '$(test-wrapper-env)' "
"'$(run-program-env)' > $@; $(evaluate-test)\n")

View File

@ -1,589 +0,0 @@
commit 15a0c5730d1d5aeb95f50c9ec7470640084feae8
Author: Chung-Lin Tang <cltang@codesourcery.com>
Date: Thu Oct 21 21:41:22 2021 +0800
elf: Fix slow DSO sorting behavior in dynamic loader (BZ #17645)
This second patch contains the actual implementation of a new sorting algorithm
for shared objects in the dynamic loader, which solves the slow behavior that
the current "old" algorithm falls into when the DSO set contains circular
dependencies.
The new algorithm implemented here is simply depth-first search (DFS) to obtain
the Reverse-Post Order (RPO) sequence, a topological sort. A new l_visited:1
bitfield is added to struct link_map to more elegantly facilitate such a search.
The DFS algorithm is applied to the input maps[nmap-1] backwards towards
maps[0]. This has the effect of a more "shallow" recursion depth in general
since the input is in BFS. Also, when combined with the natural order of
processing l_initfini[] at each node, this creates a resulting output sorting
closer to the intuitive "left-to-right" order in most cases.
Another notable implementation adjustment related to this _dl_sort_maps change
is the removing of two char arrays 'used' and 'done' in _dl_close_worker to
represent two per-map attributes. This has been changed to simply use two new
bit-fields l_map_used:1, l_map_done:1 added to struct link_map. This also allows
discarding the clunky 'used' array sorting that _dl_sort_maps had to sometimes
do along the way.
Tunable support for switching between different sorting algorithms at runtime is
also added. A new tunable 'glibc.rtld.dynamic_sort' with current valid values 1
(old algorithm) and 2 (new DFS algorithm) has been added. At time of commit
of this patch, the default setting is 1 (old algorithm).
Signed-off-by: Chung-Lin Tang <cltang@codesourcery.com>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
elf/dl-tunables.list
(No mem.tagging tunable downstream.)
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 74ca9a85dd309780..22225efb3226c3e1 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -167,8 +167,6 @@ _dl_close_worker (struct link_map *map, bool force)
bool any_tls = false;
const unsigned int nloaded = ns->_ns_nloaded;
- char used[nloaded];
- char done[nloaded];
struct link_map *maps[nloaded];
/* Run over the list and assign indexes to the link maps and enter
@@ -176,24 +174,21 @@ _dl_close_worker (struct link_map *map, bool force)
int idx = 0;
for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next)
{
+ l->l_map_used = 0;
+ l->l_map_done = 0;
l->l_idx = idx;
maps[idx] = l;
++idx;
-
}
assert (idx == nloaded);
- /* Prepare the bitmaps. */
- memset (used, '\0', sizeof (used));
- memset (done, '\0', sizeof (done));
-
/* Keep track of the lowest index link map we have covered already. */
int done_index = -1;
while (++done_index < nloaded)
{
struct link_map *l = maps[done_index];
- if (done[done_index])
+ if (l->l_map_done)
/* Already handled. */
continue;
@@ -204,12 +199,12 @@ _dl_close_worker (struct link_map *map, bool force)
/* See CONCURRENCY NOTES in cxa_thread_atexit_impl.c to know why
acquire is sufficient and correct. */
&& atomic_load_acquire (&l->l_tls_dtor_count) == 0
- && !used[done_index])
+ && !l->l_map_used)
continue;
/* We need this object and we handle it now. */
- done[done_index] = 1;
- used[done_index] = 1;
+ l->l_map_used = 1;
+ l->l_map_done = 1;
/* Signal the object is still needed. */
l->l_idx = IDX_STILL_USED;
@@ -225,9 +220,9 @@ _dl_close_worker (struct link_map *map, bool force)
{
assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
- if (!used[(*lp)->l_idx])
+ if (!(*lp)->l_map_used)
{
- used[(*lp)->l_idx] = 1;
+ (*lp)->l_map_used = 1;
/* If we marked a new object as used, and we've
already processed it, then we need to go back
and process again from that point forward to
@@ -250,9 +245,9 @@ _dl_close_worker (struct link_map *map, bool force)
{
assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
- if (!used[jmap->l_idx])
+ if (!jmap->l_map_used)
{
- used[jmap->l_idx] = 1;
+ jmap->l_map_used = 1;
if (jmap->l_idx - 1 < done_index)
done_index = jmap->l_idx - 1;
}
@@ -262,8 +257,7 @@ _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 + (nsid == LM_ID_BASE), nloaded - (nsid == LM_ID_BASE),
- used + (nsid == LM_ID_BASE), true);
+ _dl_sort_maps (maps, nloaded, (nsid == LM_ID_BASE), true);
/* Call all termination functions at once. */
bool unload_any = false;
@@ -277,7 +271,7 @@ _dl_close_worker (struct link_map *map, bool force)
/* All elements must be in the same namespace. */
assert (imap->l_ns == nsid);
- if (!used[i])
+ if (!imap->l_map_used)
{
assert (imap->l_type == lt_loaded && !imap->l_nodelete_active);
@@ -315,7 +309,7 @@ _dl_close_worker (struct link_map *map, bool force)
if (i < first_loaded)
first_loaded = i;
}
- /* Else used[i]. */
+ /* Else imap->l_map_used. */
else if (imap->l_type == lt_loaded)
{
struct r_scope_elem *new_list = NULL;
@@ -524,7 +518,7 @@ _dl_close_worker (struct link_map *map, bool force)
for (unsigned int i = first_loaded; i < nloaded; ++i)
{
struct link_map *imap = maps[i];
- if (!used[i])
+ if (!imap->l_map_used)
{
assert (imap->l_type == lt_loaded);
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 007069f670eced95..9365d54c8e03e5f4 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -612,10 +612,9 @@ Filters not supported with LD_TRACE_PRELINKING"));
/* If libc.so.6 is the main map, it participates in the sort, so
that the relocation order is correct regarding libc.so.6. */
- if (l_initfini[0] == GL (dl_ns)[l_initfini[0]->l_ns].libc_map)
- _dl_sort_maps (l_initfini, nlist, NULL, false);
- else
- _dl_sort_maps (&l_initfini[1], nlist - 1, NULL, false);
+ _dl_sort_maps (l_initfini, nlist,
+ (l_initfini[0] != GL (dl_ns)[l_initfini[0]->l_ns].libc_map),
+ false);
/* Terminate the list of dependencies. */
l_initfini[nlist] = NULL;
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index eea9d8aad736a99e..e14259a3c8806e0d 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -95,8 +95,7 @@ _dl_fini (void)
/* Now we have to do the sorting. We can skip looking for the
binary itself which is at the front of the search list for
the main namespace. */
- _dl_sort_maps (maps + (ns == LM_ID_BASE), nmaps - (ns == LM_ID_BASE),
- NULL, true);
+ _dl_sort_maps (maps, nmaps, (ns == LM_ID_BASE), true);
/* We do not rely on the linked list of loaded object anymore
from this point on. We have our own list here (maps). The
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
index b2a01ede627be1e9..398a08f28c4d9ff1 100644
--- a/elf/dl-sort-maps.c
+++ b/elf/dl-sort-maps.c
@@ -16,16 +16,24 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <assert.h>
#include <ldsodefs.h>
+#include <elf/dl-tunables.h>
+/* Note: this is the older, "original" sorting algorithm, being used as
+ default up to 2.35.
-/* Sort array MAPS according to dependencies of the contained objects.
- Array USED, if non-NULL, is permutated along MAPS. If FOR_FINI this is
- called for finishing an object. */
-void
-_dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
- bool for_fini)
+ Sort array MAPS according to dependencies of the contained objects.
+ If FOR_FINI is true, this is called for finishing an object. */
+static void
+_dl_sort_maps_original (struct link_map **maps, unsigned int nmaps,
+ unsigned int skip, bool for_fini)
{
+ /* Allows caller to do the common optimization of skipping the first map,
+ usually the main binary. */
+ maps += skip;
+ nmaps -= skip;
+
/* A list of one element need not be sorted. */
if (nmaps <= 1)
return;
@@ -66,14 +74,6 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
(k - i) * sizeof (maps[0]));
maps[k] = thisp;
- if (used != NULL)
- {
- char here_used = used[i];
- memmove (&used[i], &used[i + 1],
- (k - i) * sizeof (used[0]));
- used[k] = here_used;
- }
-
if (seen[i + 1] > nmaps - i)
{
++i;
@@ -120,3 +120,183 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, char *used,
next:;
}
}
+
+#if !HAVE_TUNABLES
+/* In this case, just default to the original algorithm. */
+strong_alias (_dl_sort_maps_original, _dl_sort_maps);
+#else
+
+/* We use a recursive function due to its better clarity and ease of
+ implementation, as well as faster execution speed. We already use
+ alloca() for list allocation during the breadth-first search of
+ dependencies in _dl_map_object_deps(), and this should be on the
+ same order of worst-case stack usage.
+
+ Note: the '*rpo' parameter is supposed to point to one past the
+ last element of the array where we save the sort results, and is
+ decremented before storing the current map at each level. */
+
+static void
+dfs_traversal (struct link_map ***rpo, struct link_map *map,
+ bool *do_reldeps)
+{
+ if (map->l_visited)
+ return;
+
+ map->l_visited = 1;
+
+ if (map->l_initfini)
+ {
+ for (int i = 0; map->l_initfini[i] != NULL; i++)
+ {
+ struct link_map *dep = map->l_initfini[i];
+ if (dep->l_visited == 0
+ && dep->l_main_map == 0)
+ dfs_traversal (rpo, dep, do_reldeps);
+ }
+ }
+
+ if (__glibc_unlikely (do_reldeps != NULL && map->l_reldeps != NULL))
+ {
+ /* Indicate that we encountered relocation dependencies during
+ traversal. */
+ *do_reldeps = true;
+
+ for (int m = map->l_reldeps->act - 1; m >= 0; m--)
+ {
+ struct link_map *dep = map->l_reldeps->list[m];
+ if (dep->l_visited == 0
+ && dep->l_main_map == 0)
+ dfs_traversal (rpo, dep, do_reldeps);
+ }
+ }
+
+ *rpo -= 1;
+ **rpo = map;
+}
+
+/* Topologically sort array MAPS according to dependencies of the contained
+ objects. */
+
+static void
+_dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps,
+ unsigned int skip __attribute__ ((unused)), bool for_fini)
+{
+ for (int i = nmaps - 1; i >= 0; i--)
+ maps[i]->l_visited = 0;
+
+ /* We apply DFS traversal for each of maps[i] until the whole total order
+ is found and we're at the start of the Reverse-Postorder (RPO) sequence,
+ which is a topological sort.
+
+ We go from maps[nmaps - 1] backwards towards maps[0] at this level.
+ Due to the breadth-first search (BFS) ordering we receive, going
+ backwards usually gives a more shallow depth-first recursion depth,
+ adding more stack usage safety. Also, combined with the natural
+ processing order of l_initfini[] at each node during DFS, this maintains
+ an ordering closer to the original link ordering in the sorting results
+ under most simpler cases.
+
+ Another reason we order the top level backwards, it that maps[0] is
+ usually exactly the main object of which we're in the midst of
+ _dl_map_object_deps() processing, and maps[0]->l_initfini[] is still
+ blank. If we start the traversal from maps[0], since having no
+ dependencies yet filled in, maps[0] will always be immediately
+ incorrectly placed at the last place in the order (first in reverse).
+ Adjusting the order so that maps[0] is last traversed naturally avoids
+ this problem.
+
+ Further, the old "optimization" of skipping the main object at maps[0]
+ from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general
+ no longer valid, since traversing along object dependency-links
+ may "find" the main object even when it is not included in the initial
+ order (e.g. a dlopen()'ed shared object can have circular dependencies
+ linked back to itself). In such a case, traversing N-1 objects will
+ create a N-object result, and raise problems.
+
+ To summarize, just passing in the full list, and iterating from back
+ to front makes things much more straightforward. */
+
+ /* Array to hold RPO sorting results, before we copy back to maps[]. */
+ struct link_map *rpo[nmaps];
+
+ /* The 'head' position during each DFS iteration. Note that we start at
+ one past the last element due to first-decrement-then-store (see the
+ bottom of above dfs_traversal() routine). */
+ struct link_map **rpo_head = &rpo[nmaps];
+
+ bool do_reldeps = false;
+ bool *do_reldeps_ref = (for_fini ? &do_reldeps : NULL);
+
+ for (int i = nmaps - 1; i >= 0; i--)
+ {
+ dfs_traversal (&rpo_head, maps[i], do_reldeps_ref);
+
+ /* We can break early if all objects are already placed. */
+ if (rpo_head == rpo)
+ goto end;
+ }
+ assert (rpo_head == rpo);
+
+ end:
+ /* Here we may do a second pass of sorting, using only l_initfini[]
+ static dependency links. This is avoided if !FOR_FINI or if we didn't
+ find any reldeps in the first DFS traversal.
+
+ The reason we do this is: while it is unspecified how circular
+ dependencies should be handled, the presumed reasonable behavior is to
+ have destructors to respect static dependency links as much as possible,
+ overriding reldeps if needed. And the first sorting pass, which takes
+ l_initfini/l_reldeps links equally, may not preserve this priority.
+
+ Hence we do a 2nd sorting pass, taking only DT_NEEDED links into account
+ (see how the do_reldeps argument to dfs_traversal() is NULL below). */
+ if (do_reldeps)
+ {
+ for (int i = nmaps - 1; i >= 0; i--)
+ rpo[i]->l_visited = 0;
+
+ struct link_map **maps_head = &maps[nmaps];
+ for (int i = nmaps - 1; i >= 0; i--)
+ {
+ dfs_traversal (&maps_head, rpo[i], NULL);
+
+ /* We can break early if all objects are already placed.
+ 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;
+ }
+ assert (maps_head == maps);
+ return;
+ }
+
+ memcpy (maps, rpo, sizeof (struct link_map *) * nmaps);
+}
+
+void
+_dl_sort_maps_init (void)
+{
+ int32_t algorithm = TUNABLE_GET (glibc, rtld, dynamic_sort, int32_t, NULL);
+ GLRO(dl_dso_sort_algo) = algorithm == 1 ? dso_sort_algorithm_original
+ : dso_sort_algorithm_dfs;
+}
+
+void
+_dl_sort_maps (struct link_map **maps, unsigned int nmaps,
+ unsigned int skip, bool for_fini)
+{
+ /* It can be tempting to use a static function pointer to store and call
+ the current selected sorting algorithm routine, but experimentation
+ shows that current processors still do not handle indirect branches
+ that efficiently, plus a static function pointer will involve
+ PTR_MANGLE/DEMANGLE, further impairing performance of small, common
+ input cases. A simple if-case with direct function calls appears to
+ be the fastest. */
+ if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original))
+ _dl_sort_maps_original (maps, nmaps, skip, for_fini);
+ else
+ _dl_sort_maps_dfs (maps, nmaps, skip, for_fini);
+}
+
+#endif /* HAVE_TUNABLES. */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index e9943e889ef447ad..ae03aec9764e29d3 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -155,6 +155,8 @@ size_t _dl_phnum;
uint64_t _dl_hwcap __attribute__ ((nocommon));
uint64_t _dl_hwcap2 __attribute__ ((nocommon));
+enum dso_sort_algorithm _dl_dso_sort_algo;
+
/* The value of the FPU control word the kernel will preset in hardware. */
fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index 998c5d52bcab8193..4e8a986541fc4c09 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -223,6 +223,9 @@ _dl_sysdep_start (void **start_argptr,
__tunables_init (_environ);
+ /* Initialize DSO sorting algorithm after tunables. */
+ _dl_sort_maps_init ();
+
#ifdef DL_SYSDEP_INIT
DL_SYSDEP_INIT;
#endif
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 6408a8e5ae92d2c6..54ef2a921310b229 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -140,4 +140,13 @@ glibc {
default: 512
}
}
+
+ rtld {
+ dynamic_sort {
+ type: INT_32
+ minval: 1
+ maxval: 2
+ default: 1
+ }
+ }
}
diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def
index 873ddf55d91155c6..5f7f18ef270bc12d 100644
--- a/elf/dso-sort-tests-1.def
+++ b/elf/dso-sort-tests-1.def
@@ -62,5 +62,5 @@ output: b>a>{}<a<b
# 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
-xfail_output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
+output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<a<c<d<g<f<b<e];}
output(glibc.rtld.dynamic_sort=2): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[<g<f<a<b<c<d<e];}
diff --git a/elf/rtld.c b/elf/rtld.c
index b47e84ca2fb6f03c..cd2cc4024a3581c2 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1453,6 +1453,9 @@ dl_main (const ElfW(Phdr) *phdr,
main_map->l_name = (char *) "";
*user_entry = main_map->l_entry;
+ /* Set bit indicating this is the main program map. */
+ main_map->l_main_map = 1;
+
#ifdef HAVE_AUX_VECTOR
/* Adjust the on-stack auxiliary vector so that it looks like the
binary was executed directly. */
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
index 4f3f7ee4e30a2b42..118afc271057afd4 100644
--- a/elf/tst-rtld-list-tunables.exp
+++ b/elf/tst-rtld-list-tunables.exp
@@ -10,5 +10,6 @@ glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+)
glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+)
glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+)
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
+glibc.rtld.dynamic_sort: 1 (min: 1, max: 2)
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
diff --git a/include/link.h b/include/link.h
index dd491989beb41353..041ff5f753a9ee11 100644
--- a/include/link.h
+++ b/include/link.h
@@ -181,6 +181,11 @@ struct link_map
unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */
unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */
unsigned int l_reserved:2; /* Reserved for internal use. */
+ unsigned int l_main_map:1; /* Nonzero for the map of the main program. */
+ unsigned int l_visited:1; /* Used internally for map dependency
+ graph traversal. */
+ unsigned int l_map_used:1; /* These two bits are used during traversal */
+ unsigned int l_map_done:1; /* of maps in _dl_close_worker. */
unsigned int l_phdr_allocated:1; /* Nonzero if the data structure pointed
to by `l_phdr' is allocated. */
unsigned int l_soname_added:1; /* Nonzero if the SONAME is for sure in
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 43272cf885d1e3e6..c3f96cdc85208926 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -303,6 +303,17 @@ changed once allocated at process startup. The default allocation of
optional static TLS is 512 bytes and is allocated in every thread.
@end deftp
+@deftp Tunable glibc.rtld.dynamic_sort
+Sets the algorithm to use for DSO sorting, valid values are @samp{1} and
+@samp{2}. For value of @samp{1}, an older O(n^3) algorithm is used, which is
+long time tested, but may have performance issues when dependencies between
+shared objects contain cycles due to circular dependencies. When set to the
+value of @samp{2}, a different algorithm is used, which implements a
+topological sort through depth-first search, and does not exhibit the
+performance issues of @samp{1}.
+
+The default value of this tunable is @samp{1}.
+@end deftp
@node Elision Tunables
@section Elision Tunables
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 5e56550a4d556fa7..9f09a4a280396659 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -240,6 +240,13 @@ enum allowmask
};
+/* DSO sort algorithm to use (check dl-sort-maps.c). */
+enum dso_sort_algorithm
+ {
+ dso_sort_algorithm_original,
+ dso_sort_algorithm_dfs
+ };
+
struct audit_ifaces
{
void (*activity) (uintptr_t *, unsigned int);
@@ -633,6 +640,8 @@ struct rtld_global_ro
platforms. */
EXTERN uint64_t _dl_hwcap2;
+ EXTERN enum dso_sort_algorithm _dl_dso_sort_algo;
+
#ifdef SHARED
/* We add a function table to _rtld_global which is then used to
call the function instead of going through the PLT. The result
@@ -1049,7 +1058,7 @@ extern void _dl_fini (void) attribute_hidden;
/* Sort array MAPS according to dependencies of the contained objects. */
extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
- char *used, bool for_fini) attribute_hidden;
+ unsigned int skip, bool for_fini) attribute_hidden;
/* The dynamic linker calls this function before and having changing
any shared object mappings. The `r_state' member of `struct r_debug'
@@ -1167,6 +1176,9 @@ extern struct link_map * _dl_get_dl_main_map (void)
# endif
#endif
+/* Initialize the DSO sort algorithm to use. */
+extern void _dl_sort_maps_init (void) attribute_hidden;
+
/* Initialization of libpthread for statically linked applications.
If libpthread is not linked in, this is an empty function. */
void __pthread_initialize_minimal (void) weak_function;

View File

@ -1,25 +0,0 @@
commit d3bf2f5927d51258a51ac7fde04f4805f8ee294a
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Wed Nov 3 09:19:30 2021 -0300
elf: Do not run DSO sorting if tunables is not enabled
Since the argorithm selection requires tunables.
Checked on x86_64-linux-gnu with --enable-tunables=no.
diff --git a/elf/Makefile b/elf/Makefile
index e92f62f279566684..3b5e1f59e6696a2b 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -998,8 +998,10 @@ include $(objpfx)$(1).generated-makefile
endef
# Generate from each testcase description file
+ifeq (yes,$(have-tunables))
$(eval $(call include_dsosort_tests,dso-sort-tests-1.def))
$(eval $(call include_dsosort_tests,dso-sort-tests-2.def))
+endif
check-abi: $(objpfx)check-abi-ld.out
tests-special += $(objpfx)check-abi-ld.out

View File

@ -1,45 +0,0 @@
commit 1f67d8286b5da9266a138198ef1f15c27cbb0010
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Nov 15 16:28:39 2021 -0800
elf: Use a temporary file to generate Makefile fragments [BZ #28550]
1. Use a temporary file to generate Makefile fragments for DSO sorting
tests and use -include on them.
2. Add Makefile fragments to postclean-generated so that a "make clean"
removes the autogenerated fragments and a subsequent "make" regenerates
them.
This partially fixes BZ #28550.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/Makefile b/elf/Makefile
index 3b5e1f59e6696a2b..22a8060f7d3bb1a1 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -986,6 +986,7 @@ tests-special += \
# tests-special
endif
+ifndef avoid-generated
# DSO sorting tests:
# The dso-ordering-test.py script generates testcase source files in $(objpfx),
# creating a $(objpfx)<testcase-name>-dir for each testcase, and creates a
@@ -993,9 +994,14 @@ endif
define include_dsosort_tests
$(objpfx)$(1).generated-makefile: $(1)
$(PYTHON) $(..)scripts/dso-ordering-test.py \
- --description-file $$< --objpfx $(objpfx) --output-makefile $$@
-include $(objpfx)$(1).generated-makefile
+ --description-file $$< --objpfx $(objpfx) --output-makefile $$@T
+ mv $$@T $$@
+-include $(objpfx)$(1).generated-makefile
endef
+endif
+
+postclean-generated += $(objpfx)/dso-sort-tests-2.generated-makefile \
+ $(objpfx)/dso-sort-tests-2.generated-makefile
# Generate from each testcase description file
ifeq (yes,$(have-tunables))

View File

@ -1,49 +0,0 @@
commit 0884724a95b60452ad483dbe086d237d02ba624d
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Dec 14 12:37:44 2021 +0100
elf: Use new dependency sorting algorithm by default
The default has to change eventually, and there are no known failures
that require a delay.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 54ef2a921310b229..f11ca5b3e8b09b43 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -146,7 +146,7 @@ glibc {
type: INT_32
minval: 1
maxval: 2
- default: 1
+ default: 2
}
}
}
diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
index 118afc271057afd4..478ee8ab091685eb 100644
--- a/elf/tst-rtld-list-tunables.exp
+++ b/elf/tst-rtld-list-tunables.exp
@@ -10,6 +10,6 @@ glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+)
glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+)
glibc.malloc.top_pad: 0x0 (min: 0x0, max: 0x[f]+)
glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
-glibc.rtld.dynamic_sort: 1 (min: 1, max: 2)
+glibc.rtld.dynamic_sort: 2 (min: 1, max: 2)
glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10)
glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+)
diff --git a/manual/tunables.texi b/manual/tunables.texi
index c3f96cdc85208926..7b70e80391ee87f7 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -312,7 +312,7 @@ value of @samp{2}, a different algorithm is used, which implements a
topological sort through depth-first search, and does not exhibit the
performance issues of @samp{1}.
-The default value of this tunable is @samp{1}.
+The default value of this tunable is @samp{2}.
@end deftp
@node Elision Tunables

View File

@ -1,357 +0,0 @@
commit 3a0588ae48fb35384a6bd33f9b66403badfa1262
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Tue Feb 8 15:22:49 2022 -0300
elf: Fix DFS sorting algorithm for LD_TRACE_LOADED_OBJECTS with missing libraries (BZ #28868)
On _dl_map_object the underlying file is not opened in trace mode
(in other cases where the underlying file can't be opened,
_dl_map_object quits with an error). If there any missing libraries
being processed, they will not be considered on final nlist size
passed on _dl_sort_maps later in the function. And it is then used by
_dl_sort_maps_dfs on the stack allocated working maps:
222 /* Array to hold RPO sorting results, before we copy back to maps[]. */
223 struct link_map *rpo[nmaps];
224
225 /* The 'head' position during each DFS iteration. Note that we start at
226 one past the last element due to first-decrement-then-store (see the
227 bottom of above dfs_traversal() routine). */
228 struct link_map **rpo_head = &rpo[nmaps];
However while transversing the 'l_initfini' on dfs_traversal it will
still consider the l_faked maps and thus update rpo more times than the
allocated working 'rpo', overflowing the stack object.
As suggested in bugzilla, one option would be to avoid sorting the maps
for trace mode. However I think ignoring l_faked object does make
sense (there is one less constraint to call the sorting function), it
allows a slight less stack usage for trace, and it is slight simpler
solution.
The tests does trigger the stack overflow, however I tried to make
it more generic to check different scenarios or missing objects.
Checked on x86_64-linux-gnu.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflicts:
elf/Makefile
(differences in backported tests)
diff --git a/elf/Makefile b/elf/Makefile
index 22a8060f7d3bb1a1..634c3113227d64a6 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -584,6 +584,11 @@ modules-names = \
libmarkermod5-3 \
libmarkermod5-4 \
libmarkermod5-5 \
+ libtracemod1-1 \
+ libtracemod2-1 \
+ libtracemod3-1 \
+ libtracemod4-1 \
+ libtracemod5-1 \
ltglobmod1 \
ltglobmod2 \
neededobj1 \
@@ -983,6 +988,11 @@ tests-special += \
$(objpfx)tst-initorder2-cmp.out \
$(objpfx)tst-unused-dep-cmp.out \
$(objpfx)tst-unused-dep.out \
+ $(objpfx)tst-trace1.out \
+ $(objpfx)tst-trace2.out \
+ $(objpfx)tst-trace3.out \
+ $(objpfx)tst-trace4.out \
+ $(objpfx)tst-trace5.out \
# tests-special
endif
@@ -2619,6 +2629,51 @@ $(objpfx)tst-rtld-run-static.out: $(objpfx)/ldconfig
$(objpfx)tst-dlmopen-gethostbyname: $(libdl)
$(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so
+
+LDFLAGS-libtracemod1-1.so += -Wl,-soname,libtracemod1.so
+LDFLAGS-libtracemod2-1.so += -Wl,-soname,libtracemod2.so
+LDFLAGS-libtracemod3-1.so += -Wl,-soname,libtracemod3.so
+LDFLAGS-libtracemod4-1.so += -Wl,-soname,libtracemod4.so
+LDFLAGS-libtracemod5-1.so += -Wl,-soname,libtracemod5.so
+
+$(objpfx)libtracemod1-1.so: $(objpfx)libtracemod2-1.so \
+ $(objpfx)libtracemod3-1.so
+$(objpfx)libtracemod2-1.so: $(objpfx)libtracemod4-1.so \
+ $(objpfx)libtracemod5-1.so
+
+define libtracemod-x
+$(objpfx)libtracemod$(1)/libtracemod$(1).so: $(objpfx)libtracemod$(1)-1.so
+ $$(make-target-directory)
+ cp $$< $$@
+endef
+libtracemod-suffixes = 1 2 3 4 5
+$(foreach i,$(libtracemod-suffixes), $(eval $(call libtracemod-x,$(i))))
+
+define tst-trace-skeleton
+$(objpfx)tst-trace$(1).out: $(objpfx)libtracemod1/libtracemod1.so \
+ $(objpfx)libtracemod2/libtracemod2.so \
+ $(objpfx)libtracemod3/libtracemod3.so \
+ $(objpfx)libtracemod4/libtracemod4.so \
+ $(objpfx)libtracemod5/libtracemod5.so \
+ $(..)scripts/tst-ld-trace.py \
+ tst-trace$(1).exp
+ ${ $(PYTHON) $(..)scripts/tst-ld-trace.py \
+ "$(test-wrapper-env) $(elf-objpfx)$(rtld-installed-name) \
+ --library-path $(common-objpfx):$(strip $(2)) \
+ $(objpfx)libtracemod1/libtracemod1.so" tst-trace$(1).exp \
+ } > $$@; $$(evaluate-test)
+endef
+
+$(eval $(call tst-trace-skeleton,1,))
+$(eval $(call tst-trace-skeleton,2,\
+ $(objpfx)libtracemod2))
+$(eval $(call tst-trace-skeleton,3,\
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3))
+$(eval $(call tst-trace-skeleton,4,\
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3:$(objpfx)libtracemod4))
+$(eval $(call tst-trace-skeleton,5,\
+ $(objpfx)libtracemod2:$(objpfx)libtracemod3:$(objpfx)libtracemod4:$(objpfx)libtracemod5))
+
$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \
$(objpfx)tst-audit-tlsdesc-mod2.so \
$(shared-thread-library)
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 9365d54c8e03e5f4..9ff589c8562b2dd1 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -489,6 +489,8 @@ _dl_map_object_deps (struct link_map *map,
for (nlist = 0, runp = known; runp; runp = runp->next)
{
+ /* _dl_sort_maps ignores l_faked object, so it is safe to not consider
+ them for nlist. */
if (__builtin_expect (trace_mode, 0) && runp->map->l_faked)
/* This can happen when we trace the loading. */
--map->l_searchlist.r_nlist;
diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c
index 398a08f28c4d9ff1..99354dc08a010dd3 100644
--- a/elf/dl-sort-maps.c
+++ b/elf/dl-sort-maps.c
@@ -140,7 +140,9 @@ static void
dfs_traversal (struct link_map ***rpo, struct link_map *map,
bool *do_reldeps)
{
- if (map->l_visited)
+ /* _dl_map_object_deps ignores l_faked objects when calculating the
+ number of maps before calling _dl_sort_maps, ignore them as well. */
+ if (map->l_visited || map->l_faked)
return;
map->l_visited = 1;
diff --git a/elf/libtracemod1-1.c b/elf/libtracemod1-1.c
new file mode 100644
index 0000000000000000..7c89c9a5a40b9668
--- /dev/null
+++ b/elf/libtracemod1-1.c
@@ -0,0 +1 @@
+/* Empty */
diff --git a/elf/libtracemod2-1.c b/elf/libtracemod2-1.c
new file mode 100644
index 0000000000000000..7c89c9a5a40b9668
--- /dev/null
+++ b/elf/libtracemod2-1.c
@@ -0,0 +1 @@
+/* Empty */
diff --git a/elf/libtracemod3-1.c b/elf/libtracemod3-1.c
new file mode 100644
index 0000000000000000..7c89c9a5a40b9668
--- /dev/null
+++ b/elf/libtracemod3-1.c
@@ -0,0 +1 @@
+/* Empty */
diff --git a/elf/libtracemod4-1.c b/elf/libtracemod4-1.c
new file mode 100644
index 0000000000000000..7c89c9a5a40b9668
--- /dev/null
+++ b/elf/libtracemod4-1.c
@@ -0,0 +1 @@
+/* Empty */
diff --git a/elf/libtracemod5-1.c b/elf/libtracemod5-1.c
new file mode 100644
index 0000000000000000..7c89c9a5a40b9668
--- /dev/null
+++ b/elf/libtracemod5-1.c
@@ -0,0 +1 @@
+/* Empty */
diff --git a/elf/tst-trace1.exp b/elf/tst-trace1.exp
new file mode 100644
index 0000000000000000..4a6f5211a68fe2c8
--- /dev/null
+++ b/elf/tst-trace1.exp
@@ -0,0 +1,4 @@
+ld 1
+libc 1
+libtracemod2.so 0
+libtracemod3.so 0
diff --git a/elf/tst-trace2.exp b/elf/tst-trace2.exp
new file mode 100644
index 0000000000000000..e13506e2eb9aeca2
--- /dev/null
+++ b/elf/tst-trace2.exp
@@ -0,0 +1,6 @@
+ld 1
+libc 1
+libtracemod2.so 1
+libtracemod3.so 0
+libtracemod4.so 0
+libtracemod5.so 0
diff --git a/elf/tst-trace3.exp b/elf/tst-trace3.exp
new file mode 100644
index 0000000000000000..e574549d12a53d72
--- /dev/null
+++ b/elf/tst-trace3.exp
@@ -0,0 +1,6 @@
+ld 1
+libc 1
+libtracemod2.so 1
+libtracemod3.so 1
+libtracemod4.so 0
+libtracemod5.so 0
diff --git a/elf/tst-trace4.exp b/elf/tst-trace4.exp
new file mode 100644
index 0000000000000000..31ca97b35bde0009
--- /dev/null
+++ b/elf/tst-trace4.exp
@@ -0,0 +1,6 @@
+ld 1
+libc 1
+libtracemod2.so 1
+libtracemod3.so 1
+libtracemod4.so 1
+libtracemod5.so 0
diff --git a/elf/tst-trace5.exp b/elf/tst-trace5.exp
new file mode 100644
index 0000000000000000..5d7d95372656396f
--- /dev/null
+++ b/elf/tst-trace5.exp
@@ -0,0 +1,6 @@
+ld 1
+libc 1
+libtracemod2.so 1
+libtracemod3.so 1
+libtracemod4.so 1
+libtracemod5.so 1
diff --git a/scripts/tst-ld-trace.py b/scripts/tst-ld-trace.py
new file mode 100755
index 0000000000000000..f5a402800377f44b
--- /dev/null
+++ b/scripts/tst-ld-trace.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python3
+# Dump the output of LD_TRACE_LOADED_OBJECTS in architecture neutral format.
+# Copyright (C) 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
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import os
+import subprocess
+import sys
+
+try:
+ subprocess.run
+except:
+ class _CompletedProcess:
+ def __init__(self, args, returncode, stdout=None, stderr=None):
+ self.args = args
+ self.returncode = returncode
+ self.stdout = stdout
+ self.stderr = stderr
+
+ def _run(*popenargs, input=None, timeout=None, check=False, **kwargs):
+ assert(timeout is None)
+ with subprocess.Popen(*popenargs, **kwargs) as process:
+ try:
+ stdout, stderr = process.communicate(input)
+ except:
+ process.kill()
+ process.wait()
+ raise
+ returncode = process.poll()
+ if check and returncode:
+ raise subprocess.CalledProcessError(returncode, popenargs)
+ return _CompletedProcess(popenargs, returncode, stdout, stderr)
+
+ subprocess.run = _run
+
+def is_vdso(lib):
+ return lib.startswith('linux-gate') or lib.startswith('linux-vdso')
+
+
+def parse_trace(cmd, fref):
+ new_env = os.environ.copy()
+ new_env['LD_TRACE_LOADED_OBJECTS'] = '1'
+ trace_out = subprocess.run(cmd, stdout=subprocess.PIPE, check=True,
+ universal_newlines=True, env=new_env).stdout
+ trace = []
+ for line in trace_out.splitlines():
+ line = line.strip()
+ if is_vdso(line):
+ continue
+ fields = line.split('=>' if '=>' in line else ' ')
+ lib = os.path.basename(fields[0].strip())
+ if lib.startswith('ld'):
+ lib = 'ld'
+ elif lib.startswith('libc'):
+ lib = 'libc'
+ found = 1 if fields[1].strip() != 'not found' else 0
+ trace += ['{} {}'.format(lib, found)]
+ trace = sorted(trace)
+
+ reference = sorted(line.replace('\n','') for line in fref.readlines())
+
+ ret = 0 if trace == reference else 1
+ if ret != 0:
+ for i in reference:
+ if i not in trace:
+ print("Only in {}: {}".format(fref.name, i))
+ for i in trace:
+ if i not in reference:
+ print("Only in trace: {}".format(i))
+
+ sys.exit(ret)
+
+
+def get_parser():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('command',
+ help='comand to run')
+ parser.add_argument('reference',
+ help='reference file to compare')
+ return parser
+
+
+def main(argv):
+ parser = get_parser()
+ opts = parser.parse_args(argv)
+ with open(opts.reference, 'r') as fref:
+ # Remove the initial 'env' command.
+ parse_trace(opts.command.split()[1:], fref)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])

View File

@ -1,36 +0,0 @@
commit a2211c76c3b994099fd58a06d6072d7495d699cd
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Mar 18 18:18:35 2022 +0100
scripts/dso-ordering-test.py: Fix C&P error in * callrefs processing
The elf/dso-sort-tests-src subdirectory is not changed by this commit,
so it seems that the cut-and-paste error was not material.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
index bde0406be9da14fc..ee476c810c76f1b0 100644
--- a/scripts/dso-ordering-test.py
+++ b/scripts/dso-ordering-test.py
@@ -551,17 +551,17 @@ def process_testcase(t):
if obj in t.deps:
deps = t.deps[obj]
if '*' in deps:
- t.deps[obj].remove('*')
+ deps.remove('*')
t.add_deps([obj], non_dep_tgt_objs)
if obj in t.callrefs:
deps = t.callrefs[obj]
if '*' in deps:
- t.deps[obj].remove('*')
+ deps.remove('*')
t.add_callrefs([obj], non_dep_tgt_objs)
if "#" in t.deps:
deps = t.deps["#"]
if '*' in deps:
- t.deps["#"].remove('*')
+ deps.remove('*')
t.add_deps(["#"], non_dep_tgt_objs)
# If no main program was specified in dependency description, make a

View File

@ -1,37 +0,0 @@
commit 183d99737298bb3200f0610fdcd1c7549c8ed560
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Sep 6 07:38:10 2022 +0200
scripts/dso-ordering-test.py: Generate program run-time dependencies
The main program needs to depend on all shared objects, even objects
that have link-time dependencies among shared objects. Filtering
out shared objects that already have an link-time dependencies is not
necessary here; make will do this automatically.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py
index ee476c810c76f1b0..43b5ec4d920ad6a3 100644
--- a/scripts/dso-ordering-test.py
+++ b/scripts/dso-ordering-test.py
@@ -707,13 +707,12 @@ def process_testcase(t):
"\t$(compile.c) $(OUTPUT_OPTION)\n")
makefile.write (rule)
- not_depended_objs = find_objs_not_depended_on(test_descr)
- if not_depended_objs:
- depstr = ""
- for dep in not_depended_objs:
- depstr += (" $(objpfx)" + test_subdir + "/"
- + test_name + "-" + dep + ".so")
- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr))
+ # Ensure that all shared objects are built before running the
+ # test, whether there link-time dependencies or not.
+ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep)
+ for dep in test_descr.objs]
+ makefile.write("$(objpfx){}.out: {}\n".format(
+ base_test_name, " ".join(depobjs)))
# Add main executable to test-srcs
makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name))

View File

@ -1,245 +0,0 @@
From a1a486d70ebcc47a686ff5846875eacad0940e41 Mon Sep 17 00:00:00 2001
From: Eyal Itkin <eyalit@checkpoint.com>
Date: Fri, 20 Mar 2020 21:19:17 +0200
Subject: Add Safe-Linking to fastbins and tcache
Safe-Linking is a security mechanism that protects single-linked
lists (such as the fastbin and tcache) from being tampered by attackers.
The mechanism makes use of randomness from ASLR (mmap_base), and when
combined with chunk alignment integrity checks, it protects the "next"
pointers from being hijacked by an attacker.
While Safe-Unlinking protects double-linked lists (such as the small
bins), there wasn't any similar protection for attacks against
single-linked lists. This solution protects against 3 common attacks:
* Partial pointer override: modifies the lower bytes (Little Endian)
* Full pointer override: hijacks the pointer to an attacker's location
* Unaligned chunks: pointing the list to an unaligned address
The design assumes an attacker doesn't know where the heap is located,
and uses the ASLR randomness to "sign" the single-linked pointers. We
mark the pointer as P and the location in which it is stored as L, and
the calculation will be:
* PROTECT(P) := (L >> PAGE_SHIFT) XOR (P)
* *L = PROTECT(P)
This way, the random bits from the address L (which start at the bit
in the PAGE_SHIFT position), will be merged with LSB of the stored
protected pointer. This protection layer prevents an attacker from
modifying the pointer into a controlled value.
An additional check that the chunks are MALLOC_ALIGNed adds an
important layer:
* Attackers can't point to illegal (unaligned) memory addresses
* Attackers must guess correctly the alignment bits
On standard 32 bit Linux machines, an attack will directly fail 7
out of 8 times, and on 64 bit machines it will fail 15 out of 16
times.
This proposed patch was benchmarked and it's effect on the overall
performance of the heap was negligible and couldn't be distinguished
from the default variance between tests on the vanilla version. A
similar protection was added to Chromium's version of TCMalloc
in 2012, and according to their documentation it had an overhead of
less than 2%.
Reviewed-by: DJ Delorie <dj@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Adhemerval Zacnella <adhemerval.zanella@linaro.org>
diff --git a/malloc/malloc.c b/malloc/malloc.c
index f7cd29bc2f..1282863681 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -327,6 +327,18 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line,
# define MAX_TCACHE_COUNT UINT16_MAX
#endif
+/* Safe-Linking:
+ Use randomness from ASLR (mmap_base) to protect single-linked lists
+ of Fast-Bins and TCache. That is, mask the "next" pointers of the
+ lists' chunks, and also perform allocation alignment checks on them.
+ This mechanism reduces the risk of pointer hijacking, as was done with
+ Safe-Unlinking in the double-linked lists of Small-Bins.
+ It assumes a minimum page size of 4096 bytes (12 bits). Systems with
+ larger pages provide less entropy, although the pointer mangling
+ still works. */
+#define PROTECT_PTR(pos, ptr) \
+ ((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
+#define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr)
/*
REALLOC_ZERO_BYTES_FREES should be set if a call to
@@ -2157,12 +2169,15 @@ do_check_malloc_state (mstate av)
while (p != 0)
{
+ if (__glibc_unlikely (!aligned_OK (p)))
+ malloc_printerr ("do_check_malloc_state(): " \
+ "unaligned fastbin chunk detected");
/* each chunk claims to be inuse */
do_check_inuse_chunk (av, p);
total += chunksize (p);
/* chunk belongs in this bin */
assert (fastbin_index (chunksize (p)) == i);
- p = p->fd;
+ p = REVEAL_PTR (p->fd);
}
}
@@ -2923,7 +2938,7 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
detect a double free. */
e->key = tcache;
- e->next = tcache->entries[tc_idx];
+ e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]);
tcache->entries[tc_idx] = e;
++(tcache->counts[tc_idx]);
}
@@ -2934,9 +2949,11 @@ static __always_inline void *
tcache_get (size_t tc_idx)
{
tcache_entry *e = tcache->entries[tc_idx];
- tcache->entries[tc_idx] = e->next;
+ tcache->entries[tc_idx] = REVEAL_PTR (e->next);
--(tcache->counts[tc_idx]);
e->key = NULL;
+ if (__glibc_unlikely (!aligned_OK (e)))
+ malloc_printerr ("malloc(): unaligned tcache chunk detected");
return (void *) e;
}
@@ -2960,7 +2977,10 @@ tcache_thread_shutdown (void)
while (tcache_tmp->entries[i])
{
tcache_entry *e = tcache_tmp->entries[i];
- tcache_tmp->entries[i] = e->next;
+ if (__glibc_unlikely (!aligned_OK (e)))
+ malloc_printerr ("tcache_thread_shutdown(): " \
+ "unaligned tcache chunk detected");
+ tcache_tmp->entries[i] = REVEAL_PTR (e->next);
__libc_free (e);
}
}
@@ -3570,8 +3590,11 @@ _int_malloc (mstate av, size_t bytes)
victim = pp; \
if (victim == NULL) \
break; \
+ pp = REVEAL_PTR (victim->fd); \
+ if (__glibc_unlikely (!aligned_OK (pp))) \
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected"); \
} \
- while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) \
+ while ((pp = catomic_compare_and_exchange_val_acq (fb, pp, victim)) \
!= victim); \
if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
@@ -3583,8 +3606,11 @@ _int_malloc (mstate av, size_t bytes)
if (victim != NULL)
{
+ if (__glibc_unlikely (!aligned_OK (victim)))
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected");
+
if (SINGLE_THREAD_P)
- *fb = victim->fd;
+ *fb = REVEAL_PTR (victim->fd);
else
REMOVE_FB (fb, pp, victim);
if (__glibc_likely (victim != NULL))
@@ -3605,8 +3631,10 @@ _int_malloc (mstate av, size_t bytes)
while (tcache->counts[tc_idx] < mp_.tcache_count
&& (tc_victim = *fb) != NULL)
{
+ if (__glibc_unlikely (!aligned_OK (tc_victim)))
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected");
if (SINGLE_THREAD_P)
- *fb = tc_victim->fd;
+ *fb = REVEAL_PTR (tc_victim->fd);
else
{
REMOVE_FB (fb, pp, tc_victim);
@@ -4196,11 +4224,15 @@ _int_free (mstate av, mchunkptr p, int have_lock)
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
- tmp = tmp->next)
+ tmp = REVEAL_PTR (tmp->next))
+ {
+ if (__glibc_unlikely (!aligned_OK (tmp)))
+ malloc_printerr ("free(): unaligned chunk detected in tcache 2");
if (tmp == e)
malloc_printerr ("free(): double free detected in tcache 2");
/* If we get here, it was a coincidence. We've wasted a
few cycles, but don't abort. */
+ }
}
if (tcache->counts[tc_idx] < mp_.tcache_count)
@@ -4264,7 +4296,7 @@ _int_free (mstate av, mchunkptr p, int have_lock)
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
- p->fd = old;
+ p->fd = PROTECT_PTR (&p->fd, old);
*fb = p;
}
else
@@ -4274,7 +4306,8 @@ _int_free (mstate av, mchunkptr p, int have_lock)
add (i.e., double free). */
if (__builtin_expect (old == p, 0))
malloc_printerr ("double free or corruption (fasttop)");
- p->fd = old2 = old;
+ old2 = old;
+ p->fd = PROTECT_PTR (&p->fd, old);
}
while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))
!= old2);
@@ -4472,13 +4505,17 @@ static void malloc_consolidate(mstate av)
if (p != 0) {
do {
{
+ if (__glibc_unlikely (!aligned_OK (p)))
+ malloc_printerr ("malloc_consolidate(): " \
+ "unaligned fastbin chunk detected");
+
unsigned int idx = fastbin_index (chunksize (p));
if ((&fastbin (av, idx)) != fb)
malloc_printerr ("malloc_consolidate(): invalid chunk size");
}
check_inuse_chunk(av, p);
- nextp = p->fd;
+ nextp = REVEAL_PTR (p->fd);
/* Slightly streamlined version of consolidation code in free() */
size = chunksize (p);
@@ -4896,8 +4933,13 @@ int_mallinfo (mstate av, struct mallinfo *m)
for (i = 0; i < NFASTBINS; ++i)
{
- for (p = fastbin (av, i); p != 0; p = p->fd)
+ for (p = fastbin (av, i);
+ p != 0;
+ p = REVEAL_PTR (p->fd))
{
+ if (__glibc_unlikely (!aligned_OK (p)))
+ malloc_printerr ("int_mallinfo(): " \
+ "unaligned fastbin chunk detected");
++nfastblocks;
fastavail += chunksize (p);
}
@@ -5437,8 +5479,11 @@ __malloc_info (int options, FILE *fp)
while (p != NULL)
{
+ if (__glibc_unlikely (!aligned_OK (p)))
+ malloc_printerr ("__malloc_info(): " \
+ "unaligned fastbin chunk detected");
++nthissize;
- p = p->fd;
+ p = REVEAL_PTR (p->fd);
}
fastavail += nthissize * thissize;

View File

@ -1,87 +0,0 @@
From 768358b6a80742f6be68ecd9f952f4b60614df96 Mon Sep 17 00:00:00 2001
From: Eyal Itkin <eyalit@checkpoint.com>
Date: Tue, 31 Mar 2020 01:55:13 -0400
Subject: Typo fixes and CR cleanup in Safe-Linking
Removed unneeded '\' chars from end of lines and fixed some
indentation issues that were introduced in the original
Safe-Linking patch.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 1282863681..0e4acb22f6 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2170,7 +2170,7 @@ do_check_malloc_state (mstate av)
while (p != 0)
{
if (__glibc_unlikely (!aligned_OK (p)))
- malloc_printerr ("do_check_malloc_state(): " \
+ malloc_printerr ("do_check_malloc_state(): "
"unaligned fastbin chunk detected");
/* each chunk claims to be inuse */
do_check_inuse_chunk (av, p);
@@ -2977,9 +2977,9 @@ tcache_thread_shutdown (void)
while (tcache_tmp->entries[i])
{
tcache_entry *e = tcache_tmp->entries[i];
- if (__glibc_unlikely (!aligned_OK (e)))
- malloc_printerr ("tcache_thread_shutdown(): " \
- "unaligned tcache chunk detected");
+ if (__glibc_unlikely (!aligned_OK (e)))
+ malloc_printerr ("tcache_thread_shutdown(): "
+ "unaligned tcache chunk detected");
tcache_tmp->entries[i] = REVEAL_PTR (e->next);
__libc_free (e);
}
@@ -4225,14 +4225,14 @@ _int_free (mstate av, mchunkptr p, int have_lock)
for (tmp = tcache->entries[tc_idx];
tmp;
tmp = REVEAL_PTR (tmp->next))
- {
- if (__glibc_unlikely (!aligned_OK (tmp)))
- malloc_printerr ("free(): unaligned chunk detected in tcache 2");
- if (tmp == e)
- malloc_printerr ("free(): double free detected in tcache 2");
- /* If we get here, it was a coincidence. We've wasted a
- few cycles, but don't abort. */
- }
+ {
+ if (__glibc_unlikely (!aligned_OK (tmp)))
+ malloc_printerr ("free(): unaligned chunk detected in tcache 2");
+ if (tmp == e)
+ malloc_printerr ("free(): double free detected in tcache 2");
+ /* If we get here, it was a coincidence. We've wasted a
+ few cycles, but don't abort. */
+ }
}
if (tcache->counts[tc_idx] < mp_.tcache_count)
@@ -4506,7 +4506,7 @@ static void malloc_consolidate(mstate av)
do {
{
if (__glibc_unlikely (!aligned_OK (p)))
- malloc_printerr ("malloc_consolidate(): " \
+ malloc_printerr ("malloc_consolidate(): "
"unaligned fastbin chunk detected");
unsigned int idx = fastbin_index (chunksize (p));
@@ -4938,7 +4938,7 @@ int_mallinfo (mstate av, struct mallinfo *m)
p = REVEAL_PTR (p->fd))
{
if (__glibc_unlikely (!aligned_OK (p)))
- malloc_printerr ("int_mallinfo(): " \
+ malloc_printerr ("int_mallinfo(): "
"unaligned fastbin chunk detected");
++nfastblocks;
fastavail += chunksize (p);
@@ -5480,7 +5480,7 @@ __malloc_info (int options, FILE *fp)
while (p != NULL)
{
if (__glibc_unlikely (!aligned_OK (p)))
- malloc_printerr ("__malloc_info(): " \
+ malloc_printerr ("__malloc_info(): "
"unaligned fastbin chunk detected");
++nthissize;
p = REVEAL_PTR (p->fd);

View File

@ -1,100 +0,0 @@
From 49c3c37651e2d2ec4ff8ce21252bbbc08a9d6639 Mon Sep 17 00:00:00 2001
From: Eyal Itkin <eyalit@checkpoint.com>
Date: Tue, 31 Mar 2020 02:00:14 -0400
Subject: Fix alignment bug in Safe-Linking
Alignment checks should be performed on the user's buffer and NOT
on the mchunkptr as was done before. This caused bugs in 32 bit
versions, because: 2*sizeof(t) != MALLOC_ALIGNMENT.
As the tcache works on users' buffers it uses the aligned_OK()
check, and the rest work on mchunkptr and therefore check using
misaligned_chunk().
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 0e4acb22f6..6acb5ad43a 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2169,7 +2169,7 @@ do_check_malloc_state (mstate av)
while (p != 0)
{
- if (__glibc_unlikely (!aligned_OK (p)))
+ if (__glibc_unlikely (misaligned_chunk (p)))
malloc_printerr ("do_check_malloc_state(): "
"unaligned fastbin chunk detected");
/* each chunk claims to be inuse */
@@ -2949,11 +2949,11 @@ static __always_inline void *
tcache_get (size_t tc_idx)
{
tcache_entry *e = tcache->entries[tc_idx];
+ if (__glibc_unlikely (!aligned_OK (e)))
+ malloc_printerr ("malloc(): unaligned tcache chunk detected");
tcache->entries[tc_idx] = REVEAL_PTR (e->next);
--(tcache->counts[tc_idx]);
e->key = NULL;
- if (__glibc_unlikely (!aligned_OK (e)))
- malloc_printerr ("malloc(): unaligned tcache chunk detected");
return (void *) e;
}
@@ -3591,7 +3591,7 @@ _int_malloc (mstate av, size_t bytes)
if (victim == NULL) \
break; \
pp = REVEAL_PTR (victim->fd); \
- if (__glibc_unlikely (!aligned_OK (pp))) \
+ if (__glibc_unlikely (pp != NULL && misaligned_chunk (pp))) \
malloc_printerr ("malloc(): unaligned fastbin chunk detected"); \
} \
while ((pp = catomic_compare_and_exchange_val_acq (fb, pp, victim)) \
@@ -3606,8 +3606,8 @@ _int_malloc (mstate av, size_t bytes)
if (victim != NULL)
{
- if (__glibc_unlikely (!aligned_OK (victim)))
- malloc_printerr ("malloc(): unaligned fastbin chunk detected");
+ if (__glibc_unlikely (misaligned_chunk (victim)))
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected 2");
if (SINGLE_THREAD_P)
*fb = REVEAL_PTR (victim->fd);
@@ -3631,8 +3631,8 @@ _int_malloc (mstate av, size_t bytes)
while (tcache->counts[tc_idx] < mp_.tcache_count
&& (tc_victim = *fb) != NULL)
{
- if (__glibc_unlikely (!aligned_OK (tc_victim)))
- malloc_printerr ("malloc(): unaligned fastbin chunk detected");
+ if (__glibc_unlikely (misaligned_chunk (tc_victim)))
+ malloc_printerr ("malloc(): unaligned fastbin chunk detected 3");
if (SINGLE_THREAD_P)
*fb = REVEAL_PTR (tc_victim->fd);
else
@@ -4505,7 +4505,7 @@ static void malloc_consolidate(mstate av)
if (p != 0) {
do {
{
- if (__glibc_unlikely (!aligned_OK (p)))
+ if (__glibc_unlikely (misaligned_chunk (p)))
malloc_printerr ("malloc_consolidate(): "
"unaligned fastbin chunk detected");
@@ -4937,7 +4937,7 @@ int_mallinfo (mstate av, struct mallinfo *m)
p != 0;
p = REVEAL_PTR (p->fd))
{
- if (__glibc_unlikely (!aligned_OK (p)))
+ if (__glibc_unlikely (misaligned_chunk (p)))
malloc_printerr ("int_mallinfo(): "
"unaligned fastbin chunk detected");
++nfastblocks;
@@ -5479,7 +5479,7 @@ __malloc_info (int options, FILE *fp)
while (p != NULL)
{
- if (__glibc_unlikely (!aligned_OK (p)))
+ if (__glibc_unlikely (misaligned_chunk (p)))
malloc_printerr ("__malloc_info(): "
"unaligned fastbin chunk detected");
++nthissize;

View File

@ -1,215 +0,0 @@
From 6310d570bf20348135d09e1f9de84a9ae7d06f83 Mon Sep 17 00:00:00 2001
From: Eyal Itkin <eyalit@checkpoint.com>
Date: Thu, 2 Apr 2020 07:26:35 -0400
Subject: Add tests for Safe-Linking
Adding the test "tst-safe-linking" for testing that Safe-Linking works
as expected. The test checks these 3 main flows:
* tcache protection
* fastbin protection
* malloc_consolidate() correctness
As there is a random chance of 1/16 that of the alignment will remain
correct, the test checks each flow up to 10 times, using different random
values for the pointer corruption. As a result, the chance for a false
failure of a given tested flow is 2**(-40), thus highly unlikely.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/malloc/Makefile b/malloc/Makefile
index 984045b5b9..e22cbde22d 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -39,6 +39,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
tst-malloc-too-large \
tst-malloc-stats-cancellation \
tst-tcfree1 tst-tcfree2 tst-tcfree3 \
+ tst-safe-linking \
tests-static := \
tst-interpose-static-nothread \
diff --git a/malloc/tst-safe-linking.c b/malloc/tst-safe-linking.c
new file mode 100644
index 0000000000..067b6c09cf
--- /dev/null
+++ b/malloc/tst-safe-linking.c
@@ -0,0 +1,179 @@
+/* Test reporting of Safe-Linking caught errors.
+ 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <time.h>
+#include <stdbool.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+
+/* Run CALLBACK and check that the data on standard error equals
+ EXPECTED. */
+static void
+check (const char *test, void (*callback) (void *),
+ const char *expected)
+{
+ int i, rand_mask;
+ bool success = false;
+ /* There is a chance of 1/16 that a corrupted pointer will be aligned.
+ Try multiple times so that statistical failure will be improbable. */
+ for (i = 0; i < 10 && !success; ++i)
+ {
+ rand_mask = rand () & 0xFF;
+ struct support_capture_subprocess result
+ = support_capture_subprocess (callback, &rand_mask);
+ /* Did not crash, could happen. Try again. */
+ if (strlen (result.err.buffer) == 0)
+ continue;
+ /* Crashed, must be the expected result. */
+ if (strcmp (result.err.buffer, expected) != 0)
+ {
+ support_record_failure ();
+ printf ("error: test %s unexpected standard error data\n"
+ " expected: %s\n"
+ " actual: %s\n",
+ test, expected, result.err.buffer);
+ }
+ TEST_VERIFY (WIFSIGNALED (result.status));
+ if (WIFSIGNALED (result.status))
+ TEST_VERIFY (WTERMSIG (result.status) == SIGABRT);
+ support_capture_subprocess_free (&result);
+ success = true;
+ }
+ TEST_VERIFY (success);
+}
+
+/* Implementation details must be kept in sync with malloc. */
+#define TCACHE_FILL_COUNT 7
+#define TCACHE_ALLOC_SIZE 0x20
+#define MALLOC_CONSOLIDATE_SIZE 256*1024
+
+/* Try corrupting the tcache list. */
+static void
+test_tcache (void *closure)
+{
+ int mask = ((int *)closure)[0];
+ size_t size = TCACHE_ALLOC_SIZE;
+
+ /* Populate the tcache list. */
+ void * volatile a = malloc (size);
+ void * volatile b = malloc (size);
+ void * volatile c = malloc (size);
+ free (a);
+ free (b);
+ free (c);
+
+ /* Corrupt the pointer with a random value, and avoid optimizations. */
+ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
+ memset (c, mask & 0xFF, size);
+ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
+
+ c = malloc (size);
+ /* This line will trigger the Safe-Linking check. */
+ b = malloc (size);
+ printf ("b=%p\n", b);
+}
+
+/* Try corrupting the fastbin list. */
+static void
+test_fastbin (void *closure)
+{
+ int i;
+ int mask = ((int *)closure)[0];
+ size_t size = TCACHE_ALLOC_SIZE;
+
+ /* Take the tcache out of the game. */
+ for (i = 0; i < TCACHE_FILL_COUNT; ++i)
+ {
+ void * volatile p = calloc (1, size);
+ free (p);
+ }
+
+ /* Populate the fastbin list. */
+ void * volatile a = calloc (1, size);
+ void * volatile b = calloc (1, size);
+ void * volatile c = calloc (1, size);
+ free (a);
+ free (b);
+ free (c);
+
+ /* Corrupt the pointer with a random value, and avoid optimizations. */
+ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
+ memset (c, mask & 0xFF, size);
+ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
+
+ c = calloc (1, size);
+ /* This line will trigger the Safe-Linking check. */
+ b = calloc (1, size);
+ printf ("b=%p\n", b);
+}
+
+/* Try corrupting the fastbin list and trigger a consolidate. */
+static void
+test_fastbin_consolidate (void *closure)
+{
+ int i;
+ int mask = ((int*)closure)[0];
+ size_t size = TCACHE_ALLOC_SIZE;
+
+ /* Take the tcache out of the game. */
+ for (i = 0; i < TCACHE_FILL_COUNT; ++i)
+ {
+ void * volatile p = calloc (1, size);
+ free (p);
+ }
+
+ /* Populate the fastbin list. */
+ void * volatile a = calloc (1, size);
+ void * volatile b = calloc (1, size);
+ void * volatile c = calloc (1, size);
+ free (a);
+ free (b);
+ free (c);
+
+ /* Corrupt the pointer with a random value, and avoid optimizations. */
+ printf ("Before: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
+ memset (c, mask & 0xFF, size);
+ printf ("After: c=%p, c[0]=%p\n", c, ((void **)c)[0]);
+
+ /* This line will trigger the Safe-Linking check. */
+ b = malloc (MALLOC_CONSOLIDATE_SIZE);
+ printf ("b=%p\n", b);
+}
+
+static int
+do_test (void)
+{
+ /* Seed the random for the test. */
+ srand (time (NULL));
+
+ check ("test_tcache", test_tcache,
+ "malloc(): unaligned tcache chunk detected\n");
+ check ("test_fastbin", test_fastbin,
+ "malloc(): unaligned fastbin chunk detected 2\n");
+ check ("test_fastbin_consolidate", test_fastbin_consolidate,
+ "malloc_consolidate(): unaligned fastbin chunk detected\n");
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -1,35 +0,0 @@
From b9cde4e3aa1ff338da7064daf1386b2f4a7351ba Mon Sep 17 00:00:00 2001
From: DJ Delorie <dj@redhat.com>
Date: Sat, 4 Apr 2020 01:44:56 -0400
Subject: malloc: ensure set_max_fast never stores zero [BZ #25733]
The code for set_max_fast() stores an "impossibly small value"
instead of zero, when the parameter is zero. However, for
small values of the parameter (ex: 1 or 2) the computation
results in a zero being stored anyway.
This patch checks for the parameter being small enough for the
computation to result in zero instead, so that a zero is never
stored.
key values which result in zero being stored:
x86-64: 1..7 (or other 64-bit)
i686: 1..11
armhfp: 1..3 (or other 32-bit)
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 6acb5ad43a..ee87ddbbf9 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1632,7 +1632,7 @@ static INTERNAL_SIZE_T global_max_fast;
*/
#define set_max_fast(s) \
- global_max_fast = (((s) == 0) \
+ global_max_fast = (((size_t) (s) <= MALLOC_ALIGN_MASK - SIZE_SZ) \
? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
static inline INTERNAL_SIZE_T

View File

@ -1,35 +0,0 @@
From 0e00b35704e67c499c3abfbd5b6224a13d38b012 Mon Sep 17 00:00:00 2001
From: "W. Hashimoto" <ssmallkirby@gmail.com>
Date: Fri, 11 Dec 2020 16:59:10 -0500
Subject: malloc: Detect infinite-loop in _int_free when freeing tcache
[BZ#27052]
If linked-list of tcache contains a loop, it invokes infinite
loop in _int_free when freeing tcache. The PoC which invokes
such infinite loop is on the Bugzilla(#27052). This loop
should terminate when the loop exceeds mp_.tcache_count and
the program should abort. The affected glibc version is
2.29 or later.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 5b87bdb081..ec2d934595 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -4224,11 +4224,14 @@ _int_free (mstate av, mchunkptr p, int have_lock)
if (__glibc_unlikely (e->key == tcache))
{
tcache_entry *tmp;
+ size_t cnt = 0;
LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
for (tmp = tcache->entries[tc_idx];
tmp;
- tmp = REVEAL_PTR (tmp->next))
+ tmp = REVEAL_PTR (tmp->next), ++cnt)
{
+ if (cnt >= mp_.tcache_count)
+ malloc_printerr ("free(): too many chunks detected in tcache");
if (__glibc_unlikely (!aligned_OK (tmp)))
malloc_printerr ("free(): unaligned chunk detected in tcache 2");
if (tmp == e)

View File

@ -1,133 +0,0 @@
From fc859c304898a5ec72e0ba5269ed136ed0ea10e1 Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Wed, 7 Jul 2021 23:02:46 +0530
Subject: Harden tcache double-free check
The tcache allocator layer uses the tcache pointer as a key to
identify a block that may be freed twice. Since this is in the
application data area, an attacker exploiting a use-after-free could
potentially get access to the entire tcache structure through this
key. A detailed write-up was provided by Awarau here:
https://awaraucom.wordpress.com/2020/07/19/house-of-io-remastered/
Replace this static pointer use for key checking with one that is
generated at malloc initialization. The first attempt is through
getrandom with a fallback to random_bits(), which is a simple
pseudo-random number generator based on the clock. The fallback ought
to be sufficient since the goal of the randomness is only to make the
key arbitrary enough that it is very unlikely to collide with user
data.
Co-authored-by: Eyal Itkin <eyalit@checkpoint.com>
[note: context for arena.c chunk #2 changed to accomodate missing
tagging support code - DJ]
diff -rup a/malloc/arena.c b/malloc/arena.c
--- a/malloc/arena.c 2022-09-16 01:09:02.003843024 -0400
+++ b/malloc/arena.c 2022-09-16 01:25:51.879994057 -0400
@@ -286,6 +286,10 @@ extern struct dl_open_hook *_dl_open_hoo
libc_hidden_proto (_dl_open_hook);
#endif
+#if USE_TCACHE
+static void tcache_key_initialize (void);
+#endif
+
static void
ptmalloc_init (void)
{
@@ -294,6 +298,10 @@ ptmalloc_init (void)
__malloc_initialized = 0;
+#if USE_TCACHE
+ tcache_key_initialize ();
+#endif
+
#ifdef SHARED
/* In case this libc copy is in a non-default namespace, never use brk.
Likewise if dlopened from statically linked program. */
diff -rup a/malloc/malloc.c b/malloc/malloc.c
--- a/malloc/malloc.c 2022-09-16 01:09:05.491977387 -0400
+++ b/malloc/malloc.c 2022-09-16 01:25:51.883994213 -0400
@@ -247,6 +247,10 @@
/* For SINGLE_THREAD_P. */
#include <sysdep-cancel.h>
+/* For tcache double-free check. */
+#include <random-bits.h>
+#include <sys/random.h>
+
/*
Debugging:
@@ -2924,7 +2928,7 @@ typedef struct tcache_entry
{
struct tcache_entry *next;
/* This field exists to detect double frees. */
- struct tcache_perthread_struct *key;
+ uintptr_t key;
} tcache_entry;
/* There is one of these for each thread, which contains the
@@ -2941,6 +2945,31 @@ typedef struct tcache_perthread_struct
static __thread bool tcache_shutting_down = false;
static __thread tcache_perthread_struct *tcache = NULL;
+/* Process-wide key to try and catch a double-free in the same thread. */
+static uintptr_t tcache_key;
+
+/* The value of tcache_key does not really have to be a cryptographically
+ secure random number. It only needs to be arbitrary enough so that it does
+ not collide with values present in applications. If a collision does happen
+ consistently enough, it could cause a degradation in performance since the
+ entire list is checked to check if the block indeed has been freed the
+ second time. The odds of this happening are exceedingly low though, about 1
+ in 2^wordsize. There is probably a higher chance of the performance
+ degradation being due to a double free where the first free happened in a
+ different thread; that's a case this check does not cover. */
+static void
+tcache_key_initialize (void)
+{
+ if (__getrandom (&tcache_key, sizeof(tcache_key), GRND_NONBLOCK)
+ != sizeof (tcache_key))
+ {
+ tcache_key = random_bits ();
+#if __WORDSIZE == 64
+ tcache_key = (tcache_key << 32) | random_bits ();
+#endif
+ }
+}
+
/* Caller must ensure that we know tc_idx is valid and there's room
for more chunks. */
static __always_inline void
@@ -2950,7 +2979,7 @@ tcache_put (mchunkptr chunk, size_t tc_i
/* Mark this chunk as "in the tcache" so the test in _int_free will
detect a double free. */
- e->key = tcache;
+ e->key = tcache_key;
e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]);
tcache->entries[tc_idx] = e;
@@ -2967,7 +2996,7 @@ tcache_get (size_t tc_idx)
malloc_printerr ("malloc(): unaligned tcache chunk detected");
tcache->entries[tc_idx] = REVEAL_PTR (e->next);
--(tcache->counts[tc_idx]);
- e->key = NULL;
+ e->key = 0;
return (void *) e;
}
@@ -4231,7 +4260,7 @@ _int_free (mstate av, mchunkptr p, int h
trust it (it also matches random payload data at a 1 in
2^<size_t> chance), so verify it's not an unlikely
coincidence before aborting. */
- if (__glibc_unlikely (e->key == tcache))
+ if (__glibc_unlikely (e->key == tcache_key))
{
tcache_entry *tmp;
size_t cnt = 0;

View File

@ -1,767 +0,0 @@
This patch is a RHEL-8.7 backport of the following upstream commit:
commit 52a103e237329b9f88a28513fe7506ffc3bd8ced
Author: Arjun Shankar <arjun@redhat.com>
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 <adhemerval.zanella@linaro.org>
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 <adhemerval.zanella@linaro.org>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <string.h>
#include <fork.h>
#include <atomic.h>
+#include <intprops.h>
+#include <stdio.h>
#define DYNARRAY_ELEMENT struct fork_handler
#define DYNARRAY_STRUCT fork_handler_list
@@ -29,7 +31,7 @@
#include <malloc/dynarray-skeleton.c>
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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include <support/check.h>
+#include <support/xthread.h>
+#include <support/capture_subprocess.h>
+#include <support/xdlfcn.h>
+
+/* 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 <support/test-driver.c>
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
+ <http://www.gnu.org/licenses/>. */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include <support/check.h>
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdlfcn.h>
+#include <stdio.h>
+#include <support/xthread.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <stdlib.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <pthread.h>
+#include <stdlib.h>
+
+/* 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),

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
commit 2a08b6e8331a611dc29325bfa6e29fecc9a3a46e
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <eggert@cs.ucla.edu>
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

View File

@ -1,90 +0,0 @@
commit 2bbd07c715275eb6c616988925738a0517180d57
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include <support/check.h>
+#include <support/support.h>
+
+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 <support/test-driver.c>
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);

View File

@ -1,41 +0,0 @@
commit 86bf0feb0e3ec8e37872f72499d6ae33406561d7
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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

View File

@ -1,295 +0,0 @@
commit db27f1251b008280a29d540b4f8ab2a38a0d80af
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
# 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"

View File

@ -1,101 +0,0 @@
commit c43c5796121bc5bcc0867f02e5536874aa8196c1
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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)))

View File

@ -1,43 +0,0 @@
commit 7163ace3318d666d40771f5c8e7c4a148827070f
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 *

View File

@ -1,161 +0,0 @@
commit 2a3224c53653214cbba2ec23424702193c80ea3b
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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

View File

@ -1,963 +0,0 @@
commit f9de8bfe1a731c309b91d175b4f6f4aeb786effa
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
commit fadf75c370494da6a02274ebe79e45b2f22ebbd0
Author: Florian Weimer <fweimer@redhat.com>
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,')

View File

@ -1,357 +0,0 @@
commit ad6f2a010c2ce759936de4747f6e0d53991912f8
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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"

View File

@ -1,23 +0,0 @@
commit ae23fa3e5fe24daf94fc7f8e5268bb8ceeda7477
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
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 <siddhesh@sourceware.org>
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) \

View File

@ -1,136 +0,0 @@
From 07b427296b8d59f439144029d9a948f6c1ce0a31 Mon Sep 17 00:00:00 2001
From: Wilco Dijkstra <wdijkstr@arm.com>
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 <naohirot@fujitsu.com>
---
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

View File

@ -1,131 +0,0 @@
From 9bc2ed8f46d80859a5596789cc9e8cc2de84b0e7 Mon Sep 17 00:00:00 2001
From: Wilco Dijkstra <wdijkstr@arm.com>
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 <naohirot@fujitsu.com>
---
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

View File

@ -1,80 +0,0 @@
From 186092c6ba8825598ffdbf15dbf0823c771f560d Mon Sep 17 00:00:00 2001
From: Wilco Dijkstra <wdijkstr@arm.com>
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 <naohirot@fujitsu.com>
---
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

View File

@ -1,51 +0,0 @@
From e69d9981f858a38e19304e6ff5ebdf89f2cb0ba0 Mon Sep 17 00:00:00 2001
From: Wilco Dijkstra <wdijkstr@arm.com>
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 <naohirot@fujitsu.com>
---
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

View File

@ -1,96 +0,0 @@
From a5db6a5cae6a92d1675c013e5c8d972768721576 Mon Sep 17 00:00:00 2001
From: Wilco Dijkstra <wdijkstr@arm.com>
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 <naohirot@fujitsu.com>
---
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

View File

@ -1,39 +0,0 @@
From 1d9f99ce1b3788d1897cb53a76d57e973111b8fe Mon Sep 17 00:00:00 2001
From: Naohiro Tamura <naohirot@fujitsu.com>
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 <Wilco.Dijkstra@arm.com>
---
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

View File

@ -1,32 +0,0 @@
From 381b29616abb82babc8163bdf516c6da87544b35 Mon Sep 17 00:00:00 2001
From: Naohiro Tamura <naohirot@fujitsu.com>
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 <szabolcs.nagy@arm.com>
---
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 <sysdep.h>
+#undef BTI_C
+#define BTI_C
+
/* Assumptions:
*
* ARMv8.2-a, AArch64, unaligned accesses, sve
--
2.31.1

View File

@ -1,630 +0,0 @@
From b31bd11454fade731e5158b1aea40b133ae19926 Mon Sep 17 00:00:00 2001
From: Wilco Dijkstra <wdijkstr@arm.com>
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 <szabolcs.nagy@arm.com>
---
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

View File

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

View File

@ -1,31 +0,0 @@
commit 88361b408b9dbd313f15413cc2e6be0f1cafb01a
Author: H.J. Lu <hjl.tools@gmail.com>
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 <adhemerval.zanella@linaro.org>
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);

View File

@ -1,45 +0,0 @@
commit 1e1ecea62e899acb58c3fdf3b320a0833ddd0dff
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Thu Sep 30 10:29:17 2021 -0700
elf: Replace nsid with args.nsid [BZ #27609]
commit ec935dea6332cb22f9881cd1162bad156173f4b0
Author: Florian Weimer <fweimer@redhat.com>
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. */

View File

@ -1,607 +0,0 @@
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 <maskray@google.com>
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 <adhemerval.zanella@linaro.org>
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))
{

View File

@ -1,65 +0,0 @@
commit 54816ae98d57930b7c945f17485714a5574bfe47
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _LINK_H
+# error "Never include <bits/link_lavcurrent.h> directly; use <link.h> 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 <bits/link_lavcurrent.h>
/* Activity types signaled through la_activity. */
enum

View File

@ -1,388 +0,0 @@
Added $(objpfx)tst-audit18: $(libdl) in elf/Makefile since
we still have $(libdl) in RHEL8.
commit ed3ce71f5c64c5f07cbde0ef03554ea8950d8f2c
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <gnu/lib-names.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <support/xstdio.h>
+#include <support/support.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <link.h>
+
+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;
+}

View File

@ -1,160 +0,0 @@
commit aee6e90f93e285016b6cd9c8bd00402c19ba271b
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+
+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

View File

@ -1,253 +0,0 @@
commit 3dac3959a5cb585b065cef2cb8a8d909c907e202
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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 <ldsodefs.h>
+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)

View File

@ -1,156 +0,0 @@
commit c91008d3490e4e3ce29520068405f081f0d368ca
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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)

View File

@ -1,122 +0,0 @@
commit 311c9ee54ea963ff69bd3a2e6981c37e893b4c3e
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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

View File

@ -1,333 +0,0 @@
commit cda4f265c65fb6c4ce38ca1cf0a7e527c5e77cd5
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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
<https://www.gnu.org/licenses/>. */
+#include <assert.h>
#include <ldsodefs.h>
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

View File

@ -1,70 +0,0 @@
commit acdcca72940e060270e4e54d9c0457398110f409
Author: John David Anglin <danglin@gcc.gnu.org>
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 <elf/dl-runtime.c>
+
+/* 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;
+}

View File

@ -1,113 +0,0 @@
commit 0b98a8748759e88b58927882a8714109abe0a2d6
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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,

View File

@ -1,205 +0,0 @@
commit eff687e8462b0eaf65992a6031b54a4b1cd16796
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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 @@
<https://www.gnu.org/licenses/>. */
#include <assert.h>
+#include <link.h>
#include <ldsodefs.h>
+#include <dl-machine.h>
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

View File

@ -1,795 +0,0 @@
commit 8c0664e2b861fd3789602cc0b0b1922b0e20cb3a
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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 <link.h>
#include <ldsodefs.h>
#include <dl-machine.h>
+#include <dl-runtime.h>
+#include <dl-fixup-attribute.h>
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
<http://www.gnu.org/licenses/>. */
-#define IN_DL_RUNTIME 1 /* This can be tested in dl-machine.h. */
-
#include <alloca.h>
#include <stdlib.h>
#include <unistd.h>
@@ -30,19 +28,6 @@
#include <dl-runtime.h>
-#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 <stdio.h>
-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
+ <https://www.gnu.org/licenses/>. */
+
+#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 <link.h>
#include <dl-lookupcfg.h>
#include <dl-sysdep.h>
+#include <dl-fixup-attribute.h>
#include <libc-lock.h>
#include <hp-timing.h>
#include <tls.h>
@@ -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
+ <https://www.gnu.org/licenses/>. */
+
+#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

View File

@ -1,449 +0,0 @@
Added $(objpfx)tst-audit19a: $(libdl) to elf/Makefile since
we still need $(libdl) in RHEL8.
commit 063f9ba220f434c7f30dd65c4cff17c0c458a7cf
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <amonakov@ispras.ru>
Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <support/xdlfcn.h>
+#include <support/check.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <getopt.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#include <link.h>
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <string.h>
+#include <stdio.h>
+
+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

View File

@ -1,296 +0,0 @@
Added $(libdl) to $(objpfx)tst-audit-tlsdesc-dlopen in elf/Makefile
since we still need $(libdl) in RHEL8.
commit d1b38173c9255b1a4ae00018ad9b35404a7c74d0
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/xthread.h>
+#include <support/xdlfcn.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+__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
+ <https://www.gnu.org/licenses/>. */
+
+__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
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/xthread.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <link.h>
+
+unsigned int
+la_version (unsigned int version)
+{
+ return LAV_CURRENT;
+}

View File

@ -1,313 +0,0 @@
commit f0e23d34a7bdf6b90fba954ee741419171ac41b2
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include <support/support.h>
+#include <sys/auxv.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/auxv.h>
+
+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

View File

@ -1,170 +0,0 @@
Added $(objpfx)tst-auditmod20: $(libdl) in elf/Makefile since
we still have $(libdl) in RHEL8.
commit 484e672ddabe0a919a692520e6ac8f2580866235
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <fweimer@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+static int
+do_test (void)
+{
+ return 0;
+}
+
+#include <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <link.h>
+#include <stdlib.h>
+
+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 ();
+}

View File

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

View File

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

View File

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

View File

@ -1,245 +0,0 @@
commit 8dbb7a08ec52057819db4ee234f9429ab99eb4ae
Author: Vineet Gupta <vgupta@synopsys.com>
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 <adhemerval.zanella@linaro.org>
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 <tls.h>
#include <dl-irel.h>
+#include <dl-runtime.h>
#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 <elf/dl-runtime.c>
/* 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 <elf/dl-runtime.c>
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;
+}

View File

@ -1,520 +0,0 @@
commit 7de01e60c200c431d3469deb784da8fd4508fc15
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jan 14 20:16:05 2022 +0100
elf/Makefile: Reflow and sort most variable assignments
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
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 = \

View File

@ -1,440 +0,0 @@
Added $(objpfx)tst-audit23: $(libdl) to elf/Makefile since
we still need $(libdl) in RHEL8.
commit 5fa11a2bc94c912c3b25860065086902674537ba
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <errno.h>
+#include <getopt.h>
+#include <link.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <gnu/lib-names.h>
+#include <string.h>
+#include <stdlib.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#include <support/xdlfcn.h>
+#include <support/support.h>
+
+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 <support/test-driver.c>
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
+ <https://www.gnu.org/licenses/>. */
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/auxv.h>
+
+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;
+}

View File

@ -1,298 +0,0 @@
commit 254d3d5aef2fd8430c469e1938209ac100ebf132
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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 <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <support/xthread.h>
+#include <support/check.h>
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <link.h>
+
+#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
+ <https://www.gnu.org/licenses/>. */
+
+#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. */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
commit 80a08d0faa9b224019f895800c4d97de4e23e1aa
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
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

View File

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

View File

@ -1,112 +0,0 @@
commit 9e94f57484a2aba0fe67ea2059b5843f651887c2
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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)

View File

@ -1,44 +0,0 @@
commit bc02f1fa2fb302eb8a486794c6b7e4811229b81e
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
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[])
{

View File

@ -1,42 +0,0 @@
commit 5325233313c66aea13e86f5dd59618e9dd74b510
Author: Stefan Liebler <stli@linux.ibm.com>
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 <adhemerval.zanella@linaro.org>
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;

View File

@ -1,34 +0,0 @@
commit 3ad5dab476205d6e16156cf0511fa6884b3b0fc4
Author: Florian Weimer <fweimer@redhat.com>
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 <carlos@redhat.com>
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)

View File

@ -1,170 +0,0 @@
commit e4a2fb76efb45210c541ee3f8ef32f317783c3a8
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed May 11 20:30:49 2022 +0200
manual: Document the dlinfo function
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@rehdat.com>
(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

View File

@ -1,268 +0,0 @@
Added $(objpfx)tst-dlinfo-phdr: $(libdl) to dlfcn/Makefile since
we still need $(libdl) in RHEL8.
commit d056c212130280c0a54d9a4f72170ec621b70ce5
Author: Florian Weimer <fweimer@redhat.com>
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 <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@rehdat.com>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <link.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/auxv.h>
+
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+/* 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 <support/test-driver.c>
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.

View File

@ -1,296 +0,0 @@
commit ad43cac44a6860eaefcadadfb2acb349921e96bf
Author: Szabolcs Nagy <szabolcs.nagy@arm.com>
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 <adhemerval.zanella@linaro.org>
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])
{

View File

@ -1,22 +0,0 @@
commit 62c888b3375f82a659a55ec66b1315efa2ed026a
Author: Carlos O'Donell <carlos@redhat.com>
Date: Thu Jun 2 10:59:14 2022 -0400
elf: Add #include <sys/param.h> 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 <dl-machine.h>
#include <dl-runtime.h>
#include <dl-fixup-attribute.h>
+#include <sys/param.h>
void
_dl_audit_activity_map (struct link_map *l, int action)

View File

@ -1,98 +0,0 @@
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 <fweimer@redhat.com>
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 <adhemerval.zanella@linaro.org>
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 *

View File

@ -1,74 +0,0 @@
commit a64af8c9b6598f6d2685227f64f5ccb9b48c663c
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon May 10 10:31:41 2021 +0200
scripts/versions.awk: Add strings and hashes to <first-versions.h>
This generates new macros of this from:
They are useful for symbol lookups using _dl_lookup_direct.
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
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.
+# <https://www.gnu.org/software/gawk/manual/html_node/Ordinal-Functions.html>
+# 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;

View File

@ -1,227 +0,0 @@
Backport of the new test from this upstream commit:
commit 8dcb6d0af07fda3607b541857e4f3970a74ed55b
Author: Florian Weimer <fweimer@redhat.com>
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 <adhemerval.zanella@linaro.org>
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 <dlfcn.h> 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <gnu/lib-names.h>
+
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+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 <support/test-driver.c>
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 <dlfcn.h> 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <first-versions.h>
+#include <gnu/lib-names.h>
+#include <link.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+unsigned int
+la_version (unsigned int current)
+{
+ /* Exercise various <dlfcn.h> 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;
+}

View File

@ -1,59 +0,0 @@
commit 2a5b4f7a715921a232f67f6810268c6cd6aa0af2
Author: Florian Weimer <fweimer@redhat.com>
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 <szabolcs.nagy@arm.com>
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

View File

@ -1,224 +0,0 @@
commit b2964eb1d9a6b8ab1250e8a881cf406182da5875
Author: Florian Weimer <fweimer@redhat.com>
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 <adhemerval.zanella@linaro.org>
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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <support/check.h>
+
+/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stddef.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+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 <support/test-driver.c>
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

View File

@ -1,822 +0,0 @@
commit fada9018199c21c469ff0e731ef75c6020074ac9
Author: Florian Weimer <fweimer@redhat.com>
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 <libc-lock.h>
#include <ldsodefs.h>
#include <libc-symbols.h>
+#include <assert.h>
+#include <dlerror.h>
#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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _DLERROR_H
+#define _DLERROR_H
+
+#include <dlfcn.h>
+#include <ldsodefs.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* 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
- <http://www.gnu.org/licenses/>. */
-
-#include <set-hooks.h>
-#include <libc-symbols.h>
-#include <dlfcn.h>
-
-/* 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <dlerror.h>
+
+/* 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 <dlfcn.h>
#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
#include <support/check.h>
/* 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 @@
<http://www.gnu.org/licenses/>. */
#include <stddef.h>
+#include <string.h>
#include <support/check.h>
#include <support/xdlfcn.h>
@@ -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 <stdlib.h>
#include <set-hooks.h>
#include <libc-internal.h>
+#include <dlfcn/dlerror.h>
#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
<http://www.gnu.org/licenses/>. */
+#include <dlfcn/dlerror.h>
#include <libc-internal.h>
#include <malloc-internal.h>
#include <resolv/resolv-internal.h>
@@ -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. */

View File

@ -1,134 +0,0 @@
Added $(objpfx)tst-dlmopen-gethostbyname: $(libdl) in elf/Makefile since
we still have $(libdl) in RHEL8.
commit c2059edce20c124d1a99f1a94cc52e83b77a917a
Author: Florian Weimer <fweimer@redhat.com>
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 <siddhesh@sourceware.org>
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
+ <https://www.gnu.org/licenses/>. */
+
+#include <netdb.h>
+#include <nss.h>
+
+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
+ <https://www.gnu.org/licenses/>. */
+
+#include <support/xdlfcn.h>
+
+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 <support/test-driver.c>

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