DSO dependency sort must put new map first even if in cycle (#2128615)
Resolves: #2128615
This commit is contained in:
parent
5a600889b6
commit
6656bd38ac
37
glibc-rh2128615-1.patch
Normal file
37
glibc-rh2128615-1.patch
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
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 bde0406be9da14fc..4ffcff6136145ef1 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))
|
79
glibc-rh2128615-2.patch
Normal file
79
glibc-rh2128615-2.patch
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
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 72f4ff0e6eda3377..7c614bca5d8115c6 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 87ad2f3f4d89eb7d..8c0fe98f69a88f1e 100644
|
||||||
|
--- a/sysdeps/generic/ldsodefs.h
|
||||||
|
+++ b/sysdeps/generic/ldsodefs.h
|
||||||
|
@@ -1106,9 +1106,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'
|
90
glibc-rh2128615-3.patch
Normal file
90
glibc-rh2128615-3.patch
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
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 7c614bca5d8115c6..e8ef5e8b3588ab53 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
|
@ -148,7 +148,7 @@ end \
|
|||||||
Summary: The GNU libc libraries
|
Summary: The GNU libc libraries
|
||||||
Name: glibc
|
Name: glibc
|
||||||
Version: %{glibcversion}
|
Version: %{glibcversion}
|
||||||
Release: 45%{?dist}
|
Release: 46%{?dist}
|
||||||
|
|
||||||
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
|
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
|
||||||
# libraries.
|
# libraries.
|
||||||
@ -586,6 +586,9 @@ Patch378: glibc-upstream-2.34-306.patch
|
|||||||
Patch379: glibc-upstream-2.34-307.patch
|
Patch379: glibc-upstream-2.34-307.patch
|
||||||
Patch380: glibc-upstream-2.34-308.patch
|
Patch380: glibc-upstream-2.34-308.patch
|
||||||
Patch381: glibc-rh2118666.patch
|
Patch381: glibc-rh2118666.patch
|
||||||
|
Patch382: glibc-rh2128615-1.patch
|
||||||
|
Patch383: glibc-rh2128615-2.patch
|
||||||
|
Patch384: glibc-rh2128615-3.patch
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Continued list of core "glibc" package information:
|
# Continued list of core "glibc" package information:
|
||||||
@ -2642,6 +2645,9 @@ fi
|
|||||||
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
|
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Oct 11 2022 Florian Weimer <fweimer@redhat.com> - 2.34-46
|
||||||
|
- DSO dependency sort must put new map first even if in cycle (#2128615)
|
||||||
|
|
||||||
* Tue Oct 11 2022 Florian Weimer <fweimer@redhat.com> - 2.34-45
|
* Tue Oct 11 2022 Florian Weimer <fweimer@redhat.com> - 2.34-45
|
||||||
- Run tst-audit-tlsdesc{,-dlopen} on all architectures (#2118666)
|
- Run tst-audit-tlsdesc{,-dlopen} on all architectures (#2118666)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user