Prevented ld.so from asserting and crashing during audited library loads.
- Backport: Extend struct r_debug to support multiple namespaces [BZ #15971] - Backport: elf: Include <sysdep.h> in elf/dl-debug-symbols.S - Backport: Minor: don't call _dl_debug_update (which can have side effects) inside assert - Backport: elf: Run constructors on cyclic recursive dlopen (bug 31986) - Backport: elf: Signal LA_ACT_CONSISTENT to auditors after RT_CONSISTENT switch - Backport: elf: Signal RT_CONSISTENT after relocation processing in dlopen (bug 31986) - Backport: Revert "elf: Run constructors on cyclic recursive dlopen (bug 31986)" - Backport: elf: Test dlopen (NULL, RTLD_LAZY) from an ELF constructor - Backport: elf: Fix map_complete Systemtap probe in dl_open_worker - Backport: elf: Introduce separate _r_debug_array variable - Add downstream patch to keep the ABI stable Resolves: RHEL-47403
This commit is contained in:
parent
b8e117b06d
commit
72524e00c3
562
glibc-RHEL-47403-1.patch
Normal file
562
glibc-RHEL-47403-1.patch
Normal file
@ -0,0 +1,562 @@
|
||||
commit a93d9e03a31ec14405cb3a09aa95413b67067380
|
||||
Author: H.J. Lu <hjl.tools@gmail.com>
|
||||
Date: Tue Aug 17 19:35:48 2021 -0700
|
||||
|
||||
Extend struct r_debug to support multiple namespaces [BZ #15971]
|
||||
|
||||
Glibc does not provide an interface for debugger to access libraries
|
||||
loaded in multiple namespaces via dlmopen.
|
||||
|
||||
The current rtld-debugger interface is described in the file:
|
||||
|
||||
elf/rtld-debugger-interface.txt
|
||||
|
||||
under the "Standard debugger interface" heading. This interface only
|
||||
provides access to the first link-map (LM_ID_BASE).
|
||||
|
||||
1. Bump r_version to 2 when multiple namespaces are used. This triggers
|
||||
the GDB bug:
|
||||
|
||||
https://sourceware.org/bugzilla/show_bug.cgi?id=28236
|
||||
|
||||
2. Add struct r_debug_extended to extend struct r_debug into a linked-list,
|
||||
where each element correlates to an unique namespace.
|
||||
3. Initialize the r_debug_extended structure. Bump r_version to 2 for
|
||||
the new namespace and add the new namespace to the namespace linked list.
|
||||
4. Add _dl_debug_update to return the address of struct r_debug' of a
|
||||
namespace.
|
||||
5. Add a hidden symbol, _r_debug_extended, for struct r_debug_extended.
|
||||
6. Provide the symbol, _r_debug, with size of struct r_debug, as an alias
|
||||
of _r_debug_extended, for programs which reference _r_debug.
|
||||
|
||||
This fixes BZ #15971.
|
||||
|
||||
Reviewed-by: Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile (fixup context due to reordering)
|
||||
elf/dl-open.c (modified line didn't exist downstream)
|
||||
|
||||
diff --git a/csu/Makefile b/csu/Makefile
|
||||
index 3054329cea4a276d..e2390e4a7deb6941 100644
|
||||
--- a/csu/Makefile
|
||||
+++ b/csu/Makefile
|
||||
@@ -88,6 +88,9 @@ endif
|
||||
before-compile += $(objpfx)abi-tag.h
|
||||
generated += abi-tag.h
|
||||
|
||||
+# Put it here to generate it earlier.
|
||||
+gen-as-const-headers += rtld-sizes.sym
|
||||
+
|
||||
# These are the special initializer/finalizer files. They are always the
|
||||
# first and last file in the link. crti.o ... crtn.o define the global
|
||||
# "functions" _init and _fini to run the .init and .fini sections.
|
||||
diff --git a/csu/rtld-sizes.sym b/csu/rtld-sizes.sym
|
||||
new file mode 100644
|
||||
index 0000000000000000..13924d5efdbaa248
|
||||
--- /dev/null
|
||||
+++ b/csu/rtld-sizes.sym
|
||||
@@ -0,0 +1,6 @@
|
||||
+#include <link.h>
|
||||
+
|
||||
+--
|
||||
+R_DEBUG_SIZE sizeof (struct r_debug)
|
||||
+R_DEBUG_EXTENDED_SIZE sizeof (struct r_debug_extended)
|
||||
+R_DEBUG_EXTENDED_ALIGN __alignof (struct r_debug_extended)
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 15bec14364266c77..b074cc29664b3e20 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -54,6 +54,7 @@ dl-routines = \
|
||||
dl-catch \
|
||||
dl-close \
|
||||
dl-debug \
|
||||
+ dl-debug-symbols \
|
||||
dl-deps \
|
||||
dl-exception \
|
||||
dl-execstack \
|
||||
@@ -399,6 +400,7 @@ tests += \
|
||||
tst-dlmodcount \
|
||||
tst-dlmopen1 \
|
||||
tst-dlmopen3 \
|
||||
+ tst-dlmopen4 \
|
||||
tst-dlmopen-dlerror \
|
||||
tst-dlmopen-gethostbyname \
|
||||
tst-dlmopen-twice \
|
||||
@@ -1973,6 +1975,8 @@ $(objpfx)tst-dlmopen2.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
$(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so
|
||||
|
||||
+$(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so
|
||||
+
|
||||
$(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so
|
||||
tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index 9d158c25498fd8ae..bf699e58d753a1e2 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -469,7 +469,7 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
#endif
|
||||
|
||||
/* Notify the debugger we are about to remove some loaded objects. */
|
||||
- struct r_debug *r = _dl_debug_initialize (0, nsid);
|
||||
+ struct r_debug *r = _dl_debug_update (nsid);
|
||||
r->r_state = RT_DELETE;
|
||||
_dl_debug_state ();
|
||||
LIBC_PROBE (unmap_start, 2, nsid, r);
|
||||
diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S
|
||||
new file mode 100644
|
||||
index 0000000000000000..b7e9f5d9470c4da2
|
||||
--- /dev/null
|
||||
+++ b/elf/dl-debug-symbols.S
|
||||
@@ -0,0 +1,36 @@
|
||||
+/* Define symbols used to communicate dynamic linker state to the
|
||||
+ debugger at runtime.
|
||||
+ 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 <rtld-sizes.h>
|
||||
+
|
||||
+/* Define 2 symbols, _r_debug_extended and _r_debug, which is an alias
|
||||
+ of _r_debug_extended, but with the size of struct r_debug. */
|
||||
+
|
||||
+ .globl _r_debug
|
||||
+ .type _r_debug, %object
|
||||
+ .size _r_debug, R_DEBUG_SIZE
|
||||
+ .hidden _r_debug_extended
|
||||
+ .globl _r_debug_extended
|
||||
+ .type _r_debug_extended, %object
|
||||
+ .size _r_debug_extended, R_DEBUG_EXTENDED_SIZE
|
||||
+ .section .bss
|
||||
+ .balign R_DEBUG_EXTENDED_ALIGN
|
||||
+_r_debug:
|
||||
+_r_debug_extended:
|
||||
+ .zero R_DEBUG_EXTENDED_SIZE
|
||||
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
|
||||
index 2cd5f0975380445c..f637d4bb8de3db8c 100644
|
||||
--- a/elf/dl-debug.c
|
||||
+++ b/elf/dl-debug.c
|
||||
@@ -30,37 +30,80 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
|
||||
&& VERIFY_MEMBER (l_prev))
|
||||
? 1 : -1];
|
||||
|
||||
-/* This structure communicates dl state to the debugger. The debugger
|
||||
- normally finds it via the DT_DEBUG entry in the dynamic section, but in
|
||||
- a statically-linked program there is no dynamic section for the debugger
|
||||
- to examine and it looks for this particular symbol name. */
|
||||
-struct r_debug _r_debug;
|
||||
+/* Update the `r_map' member and return the address of `struct r_debug'
|
||||
+ of the namespace NS. */
|
||||
|
||||
+struct r_debug *
|
||||
+_dl_debug_update (Lmid_t ns)
|
||||
+{
|
||||
+ struct r_debug_extended *r;
|
||||
+ if (ns == LM_ID_BASE)
|
||||
+ r = &_r_debug_extended;
|
||||
+ else
|
||||
+ r = &GL(dl_ns)[ns]._ns_debug;
|
||||
+ if (r->base.r_map == NULL)
|
||||
+ atomic_store_release (&r->base.r_map,
|
||||
+ (void *) GL(dl_ns)[ns]._ns_loaded);
|
||||
+ return &r->base;
|
||||
+}
|
||||
|
||||
-/* Initialize _r_debug if it has not already been done. The argument is
|
||||
- the run-time load address of the dynamic linker, to be put in
|
||||
- _r_debug.r_ldbase. Returns the address of _r_debug. */
|
||||
+/* Initialize _r_debug_extended for the namespace NS. LDBASE is the
|
||||
+ run-time load address of the dynamic linker, to be put in
|
||||
+ _r_debug_extended.r_ldbase. Return the address of _r_debug. */
|
||||
|
||||
struct r_debug *
|
||||
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
{
|
||||
- struct r_debug *r;
|
||||
+ struct r_debug_extended *r, **pp = NULL;
|
||||
|
||||
if (ns == LM_ID_BASE)
|
||||
- r = &_r_debug;
|
||||
- else
|
||||
- r = &GL(dl_ns)[ns]._ns_debug;
|
||||
+ {
|
||||
+ r = &_r_debug_extended;
|
||||
+ /* Initialize r_version to 1. */
|
||||
+ if (_r_debug_extended.base.r_version == 0)
|
||||
+ _r_debug_extended.base.r_version = 1;
|
||||
+ }
|
||||
+ else if (DL_NNS > 1)
|
||||
+ {
|
||||
+ r = &GL(dl_ns)[ns]._ns_debug;
|
||||
+ if (r->base.r_brk == 0)
|
||||
+ {
|
||||
+ /* Add the new namespace to the linked list. After a namespace
|
||||
+ is initialized, r_brk becomes non-zero. A namespace becomes
|
||||
+ empty (r_map == NULL) when it is unused. But it is never
|
||||
+ removed from the linked list. */
|
||||
+ struct r_debug_extended *p;
|
||||
+ for (pp = &_r_debug_extended.r_next;
|
||||
+ (p = *pp) != NULL;
|
||||
+ pp = &p->r_next)
|
||||
+ ;
|
||||
+
|
||||
+ r->base.r_version = 2;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (r->base.r_brk == 0)
|
||||
+ {
|
||||
+ /* Tell the debugger where to find the map of loaded objects.
|
||||
+ This function is called from dlopen. Initialize the namespace
|
||||
+ only once. */
|
||||
+ r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
|
||||
+ r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
|
||||
+ r->r_next = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (r->base.r_map == NULL)
|
||||
+ atomic_store_release (&r->base.r_map,
|
||||
+ (void *) GL(dl_ns)[ns]._ns_loaded);
|
||||
|
||||
- if (r->r_map == NULL || ldbase != 0)
|
||||
+ if (pp != NULL)
|
||||
{
|
||||
- /* Tell the debugger where to find the map of loaded objects. */
|
||||
- r->r_version = 1 /* R_DEBUG_VERSION XXX */;
|
||||
- r->r_ldbase = ldbase ?: _r_debug.r_ldbase;
|
||||
- r->r_map = (void *) GL(dl_ns)[ns]._ns_loaded;
|
||||
- r->r_brk = (ElfW(Addr)) &_dl_debug_state;
|
||||
+ atomic_store_release (pp, r);
|
||||
+ /* Bump r_version to 2 for the new namespace. */
|
||||
+ atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||
}
|
||||
|
||||
- return r;
|
||||
+ return &r->base;
|
||||
}
|
||||
|
||||
|
||||
diff --git a/elf/dl-load.c b/elf/dl-load.c
|
||||
index eb6b658b698f5694..5b0734c816b351f0 100644
|
||||
--- a/elf/dl-load.c
|
||||
+++ b/elf/dl-load.c
|
||||
@@ -950,7 +950,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
/* Initialize to keep the compiler happy. */
|
||||
const char *errstring = NULL;
|
||||
int errval = 0;
|
||||
- struct r_debug *r = _dl_debug_initialize (0, nsid);
|
||||
+ struct r_debug *r = _dl_debug_update (nsid);
|
||||
bool make_consistent = false;
|
||||
|
||||
/* Get file information. To match the kernel behavior, do not fill
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 80af6518d4395906..eef724f7e9b2211d 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -596,7 +596,7 @@ dl_open_worker_begin (void *a)
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
add_to_global_update (new);
|
||||
|
||||
- assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
|
||||
+ assert (_dl_debug_update (args->nsid)->r_state == RT_CONSISTENT);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -634,7 +634,7 @@ dl_open_worker_begin (void *a)
|
||||
#endif
|
||||
|
||||
/* Notify the debugger all new objects are now ready to go. */
|
||||
- struct r_debug *r = _dl_debug_initialize (0, args->nsid);
|
||||
+ struct r_debug *r = _dl_debug_update (args->nsid);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
|
||||
@@ -840,7 +840,7 @@ no more namespaces available for dlmopen()"));
|
||||
}
|
||||
|
||||
GL(dl_ns)[nsid].libc_map = NULL;
|
||||
- _dl_debug_initialize (0, nsid)->r_state = RT_CONSISTENT;
|
||||
+ _dl_debug_update (nsid)->r_state = RT_CONSISTENT;
|
||||
}
|
||||
/* Never allow loading a DSO in a namespace which is empty. Such
|
||||
direct placements is only causing problems. Also don't allow
|
||||
@@ -916,7 +916,7 @@ no more namespaces available for dlmopen()"));
|
||||
_dl_signal_exception (errcode, &exception, NULL);
|
||||
}
|
||||
|
||||
- assert (_dl_debug_initialize (0, args.nsid)->r_state == RT_CONSISTENT);
|
||||
+ assert (_dl_debug_update (args.nsid)->r_state == RT_CONSISTENT);
|
||||
|
||||
/* Release the lock. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
|
||||
index 757205affe65d9e1..5b85df8a2eed1888 100644
|
||||
--- a/elf/dl-reloc-static-pie.c
|
||||
+++ b/elf/dl-reloc-static-pie.c
|
||||
@@ -62,7 +62,7 @@ _dl_relocate_static_pie (void)
|
||||
ELF_DYNAMIC_RELOCATE (main_map, NULL, 0, 0, 0);
|
||||
main_map->l_relocated = 1;
|
||||
|
||||
- /* Initialize _r_debug. */
|
||||
+ /* Initialize _r_debug_extended. */
|
||||
struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
|
||||
diff --git a/elf/link.h b/elf/link.h
|
||||
index 21a351686b9bf7c8..0906bbe33fbd9f8f 100644
|
||||
--- a/elf/link.h
|
||||
+++ b/elf/link.h
|
||||
@@ -34,14 +34,13 @@
|
||||
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||
#include <bits/link.h>
|
||||
|
||||
-/* Rendezvous structure used by the run-time dynamic linker to communicate
|
||||
- details of shared object loading to the debugger. If the executable's
|
||||
- dynamic section has a DT_DEBUG element, the run-time linker sets that
|
||||
- element's value to the address where this structure can be found. */
|
||||
+/* The legacy rendezvous structure used by the run-time dynamic linker to
|
||||
+ communicate details of shared object loading to the debugger. */
|
||||
|
||||
struct r_debug
|
||||
{
|
||||
- int r_version; /* Version number for this protocol. */
|
||||
+ /* Version number for this protocol. It should be greater than 0. */
|
||||
+ int r_version;
|
||||
|
||||
struct link_map *r_map; /* Head of the chain of loaded objects. */
|
||||
|
||||
@@ -63,16 +62,34 @@ struct r_debug
|
||||
ElfW(Addr) r_ldbase; /* Base address the linker is loaded at. */
|
||||
};
|
||||
|
||||
-/* This is the instance of that structure used by the dynamic linker. */
|
||||
+/* This is the symbol of that structure provided by the dynamic linker. */
|
||||
extern struct r_debug _r_debug;
|
||||
|
||||
+/* The extended rendezvous structure used by the run-time dynamic linker
|
||||
+ to communicate details of shared object loading to the debugger. If
|
||||
+ the executable's dynamic section has a DT_DEBUG element, the run-time
|
||||
+ linker sets that element's value to the address where this structure
|
||||
+ can be found. */
|
||||
+
|
||||
+struct r_debug_extended
|
||||
+ {
|
||||
+ struct r_debug base;
|
||||
+
|
||||
+ /* The following field is added by r_version == 2. */
|
||||
+
|
||||
+ /* Link to the next r_debug_extended structure. Each r_debug_extended
|
||||
+ structure represents a different namespace. The first
|
||||
+ r_debug_extended structure is for the default namespace. */
|
||||
+ struct r_debug_extended *r_next;
|
||||
+ };
|
||||
+
|
||||
/* This symbol refers to the "dynamic structure" in the `.dynamic' section
|
||||
of whatever module refers to `_DYNAMIC'. So, to find its own
|
||||
- `struct r_debug', a program could do:
|
||||
+ `struct r_debug_extended', a program could do:
|
||||
for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; ++dyn)
|
||||
if (dyn->d_tag == DT_DEBUG)
|
||||
- r_debug = (struct r_debug *) dyn->d_un.d_ptr;
|
||||
- */
|
||||
+ r_debug_extended = (struct r_debug_extended *) dyn->d_un.d_ptr;
|
||||
+ */
|
||||
extern ElfW(Dyn) _DYNAMIC[];
|
||||
|
||||
/* Structure describing a loaded shared object. The `l_next' and `l_prev'
|
||||
diff --git a/elf/rtld-debugger-interface.txt b/elf/rtld-debugger-interface.txt
|
||||
index 61bc99e4b086612f..f3476d8308616f84 100644
|
||||
--- a/elf/rtld-debugger-interface.txt
|
||||
+++ b/elf/rtld-debugger-interface.txt
|
||||
@@ -9,6 +9,9 @@ structure can be found.
|
||||
|
||||
The r_debug structure contains (amongst others) the following fields:
|
||||
|
||||
+ int r_version:
|
||||
+ Version number for this protocol. It should be greater than 0.
|
||||
+
|
||||
struct link_map *r_map:
|
||||
A linked list of loaded objects.
|
||||
|
||||
@@ -32,6 +35,18 @@ but there is no way for the debugger to discover whether any of the
|
||||
objects in the link-map have been relocated or not.
|
||||
|
||||
|
||||
+Extension to the r_debug structure
|
||||
+==================================
|
||||
+
|
||||
+The r_debug_extended structure is an extension of the r_debug interface.
|
||||
+If r_version is 2, one additional field is available:
|
||||
+
|
||||
+ struct r_debug_extended *r_next;
|
||||
+ Link to the next r_debug_extended structure. Each r_debug_extended
|
||||
+ structure represents a different namespace. A namespace is active
|
||||
+ if its r_map field isn't NULL. The first r_debug_extended structure
|
||||
+ is for the default namespace.
|
||||
+
|
||||
Probe-based debugger interface
|
||||
==============================
|
||||
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index d3d9e6b904ac78fd..7d8ed0ac1188d527 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -1725,7 +1725,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
objects. */
|
||||
call_init_paths (&state);
|
||||
|
||||
- /* Initialize _r_debug. */
|
||||
+ /* Initialize _r_debug_extended. */
|
||||
struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr,
|
||||
LM_ID_BASE);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
@@ -2531,7 +2531,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
|
||||
/* Notify the debugger all new objects are now ready to go. We must re-get
|
||||
the address since by now the variable might be in another object. */
|
||||
- r = _dl_debug_initialize (0, LM_ID_BASE);
|
||||
+ r = _dl_debug_update (LM_ID_BASE);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
|
||||
diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..3fe150e50bc259f0
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlmopen4.c
|
||||
@@ -0,0 +1,72 @@
|
||||
+/* Test struct r_debug_extended via DT_DEBUG.
|
||||
+ 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>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <gnu/lib-names.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+#include <support/check.h>
|
||||
+#include <support/test-driver.h>
|
||||
+
|
||||
+#ifndef ELF_MACHINE_GET_R_DEBUG
|
||||
+# define ELF_MACHINE_GET_R_DEBUG(d) \
|
||||
+ (__extension__ ({ \
|
||||
+ struct r_debug_extended *debug; \
|
||||
+ if ((d)->d_tag == DT_DEBUG) \
|
||||
+ debug = (struct r_debug_extended *) (d)->d_un.d_ptr; \
|
||||
+ else \
|
||||
+ debug = NULL; \
|
||||
+ debug; }))
|
||||
+#endif
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ ElfW(Dyn) *d;
|
||||
+ struct r_debug_extended *debug = NULL;
|
||||
+
|
||||
+ for (d = _DYNAMIC; d->d_tag != DT_NULL; ++d)
|
||||
+ {
|
||||
+ debug = ELF_MACHINE_GET_R_DEBUG (d);
|
||||
+ if (debug != NULL)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ TEST_VERIFY_EXIT (debug != NULL);
|
||||
+ TEST_COMPARE (debug->base.r_version, 1);
|
||||
+ TEST_VERIFY_EXIT (debug->r_next == NULL);
|
||||
+
|
||||
+ void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so",
|
||||
+ RTLD_LAZY);
|
||||
+
|
||||
+ TEST_COMPARE (debug->base.r_version, 2);
|
||||
+ TEST_VERIFY_EXIT (debug->r_next != NULL);
|
||||
+ TEST_VERIFY_EXIT (debug->r_next->r_next == NULL);
|
||||
+ TEST_VERIFY_EXIT (debug->r_next->base.r_map != NULL);
|
||||
+ TEST_VERIFY_EXIT (debug->r_next->base.r_map->l_name != NULL);
|
||||
+ const char *name = basename (debug->r_next->base.r_map->l_name);
|
||||
+ TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so");
|
||||
+
|
||||
+ xdlclose (h);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/include/link.h b/include/link.h
|
||||
index 0dc63ef37d6a5666..0cf130ddb8af2e89 100644
|
||||
--- a/include/link.h
|
||||
+++ b/include/link.h
|
||||
@@ -362,6 +362,10 @@ struct auditstate
|
||||
};
|
||||
|
||||
|
||||
+/* This is the hidden instance of struct r_debug_extended used by the
|
||||
+ dynamic linker. */
|
||||
+extern struct r_debug_extended _r_debug_extended attribute_hidden;
|
||||
+
|
||||
#if __ELF_NATIVE_CLASS == 32
|
||||
# define symbind symbind32
|
||||
# define LA_SYMBIND "la_symbind32"
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index dc4e0555e4ed7f3c..695f3910234e87da 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -376,7 +376,7 @@ struct rtld_global
|
||||
void (*free) (void *);
|
||||
} _ns_unique_sym_table;
|
||||
/* Keep track of changes to each namespace' list. */
|
||||
- struct r_debug _ns_debug;
|
||||
+ struct r_debug_extended _ns_debug;
|
||||
} _dl_ns[DL_NNS];
|
||||
/* One higher than index of last used namespace. */
|
||||
EXTERN size_t _dl_nns;
|
||||
@@ -1128,12 +1128,16 @@ extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps,
|
||||
extern void _dl_debug_state (void);
|
||||
rtld_hidden_proto (_dl_debug_state)
|
||||
|
||||
-/* Initialize `struct r_debug' if it has not already been done. The
|
||||
- argument is the run-time load address of the dynamic linker, to be put
|
||||
- in the `r_ldbase' member. Returns the address of the structure. */
|
||||
+/* Initialize `struct r_debug_extended' for the namespace NS. LDBASE
|
||||
+ is the run-time load address of the dynamic linker, to be put in the
|
||||
+ `r_ldbase' member. Return the address of the structure. */
|
||||
extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
attribute_hidden;
|
||||
|
||||
+/* Update the `r_map' member and return the address of `struct r_debug'
|
||||
+ of the namespace NS. */
|
||||
+extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden;
|
||||
+
|
||||
/* Initialize the basic data structure for the search paths. SOURCE
|
||||
is either "LD_LIBRARY_PATH" or "--library-path".
|
||||
GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to
|
||||
158
glibc-RHEL-47403-10.patch
Normal file
158
glibc-RHEL-47403-10.patch
Normal file
@ -0,0 +1,158 @@
|
||||
commit 7278d11f3a0cd528188c719bab75575b0aea2c6e
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Jul 4 21:46:05 2025 +0200
|
||||
|
||||
elf: Introduce separate _r_debug_array variable
|
||||
|
||||
It replaces the ns_debug member of the namespaces. Previously,
|
||||
the base namespace had an unused ns_debug member.
|
||||
|
||||
This change also fixes a concurrency issue: Now _dl_debug_initialize
|
||||
only updates r_next of the previous namespace's r_debug after the new
|
||||
r_debug is initialized, so that only the initialized version is
|
||||
observed. (Client code accessing _r_debug will benefit from load
|
||||
dependency tracking in CPUs even without explicit barriers.)
|
||||
|
||||
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
||||
|
||||
diff --git a/elf/dl-debug.c b/elf/dl-debug.c
|
||||
index f637d4bb8de3db8c..649386d5a6b885ed 100644
|
||||
--- a/elf/dl-debug.c
|
||||
+++ b/elf/dl-debug.c
|
||||
@@ -30,17 +30,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr)
|
||||
&& VERIFY_MEMBER (l_prev))
|
||||
? 1 : -1];
|
||||
|
||||
+#ifdef SHARED
|
||||
+/* r_debug structs for secondary namespaces. The first namespace is
|
||||
+ handled separately because its r_debug structure must overlap with
|
||||
+ the public _r_debug symbol, so the first array element corresponds
|
||||
+ to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */
|
||||
+struct r_debug_extended _r_debug_array[DL_NNS - 1];
|
||||
+
|
||||
+/* Return the r_debug object for the namespace NS. */
|
||||
+static inline struct r_debug_extended *
|
||||
+get_rdebug (Lmid_t ns)
|
||||
+{
|
||||
+ if (ns == LM_ID_BASE)
|
||||
+ return &_r_debug_extended;
|
||||
+ else
|
||||
+ return &_r_debug_array[ns - 1];
|
||||
+}
|
||||
+#else /* !SHARED */
|
||||
+static inline struct r_debug_extended *
|
||||
+get_rdebug (Lmid_t ns)
|
||||
+{
|
||||
+ return &_r_debug_extended; /* There is just one namespace. */
|
||||
+}
|
||||
+#endif /* !SHARED */
|
||||
+
|
||||
/* Update the `r_map' member and return the address of `struct r_debug'
|
||||
of the namespace NS. */
|
||||
|
||||
struct r_debug *
|
||||
_dl_debug_update (Lmid_t ns)
|
||||
{
|
||||
- struct r_debug_extended *r;
|
||||
- if (ns == LM_ID_BASE)
|
||||
- r = &_r_debug_extended;
|
||||
- else
|
||||
- r = &GL(dl_ns)[ns]._ns_debug;
|
||||
+ struct r_debug_extended *r = get_rdebug (ns);
|
||||
if (r->base.r_map == NULL)
|
||||
atomic_store_release (&r->base.r_map,
|
||||
(void *) GL(dl_ns)[ns]._ns_loaded);
|
||||
@@ -54,34 +74,7 @@ _dl_debug_update (Lmid_t ns)
|
||||
struct r_debug *
|
||||
_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
{
|
||||
- struct r_debug_extended *r, **pp = NULL;
|
||||
-
|
||||
- if (ns == LM_ID_BASE)
|
||||
- {
|
||||
- r = &_r_debug_extended;
|
||||
- /* Initialize r_version to 1. */
|
||||
- if (_r_debug_extended.base.r_version == 0)
|
||||
- _r_debug_extended.base.r_version = 1;
|
||||
- }
|
||||
- else if (DL_NNS > 1)
|
||||
- {
|
||||
- r = &GL(dl_ns)[ns]._ns_debug;
|
||||
- if (r->base.r_brk == 0)
|
||||
- {
|
||||
- /* Add the new namespace to the linked list. After a namespace
|
||||
- is initialized, r_brk becomes non-zero. A namespace becomes
|
||||
- empty (r_map == NULL) when it is unused. But it is never
|
||||
- removed from the linked list. */
|
||||
- struct r_debug_extended *p;
|
||||
- for (pp = &_r_debug_extended.r_next;
|
||||
- (p = *pp) != NULL;
|
||||
- pp = &p->r_next)
|
||||
- ;
|
||||
-
|
||||
- r->base.r_version = 2;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
+ struct r_debug_extended *r = get_rdebug (ns);
|
||||
if (r->base.r_brk == 0)
|
||||
{
|
||||
/* Tell the debugger where to find the map of loaded objects.
|
||||
@@ -89,20 +82,36 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
|
||||
only once. */
|
||||
r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase;
|
||||
r->base.r_brk = (ElfW(Addr)) &_dl_debug_state;
|
||||
- r->r_next = NULL;
|
||||
+
|
||||
+#ifdef SHARED
|
||||
+ /* Add the new namespace to the linked list. This assumes that
|
||||
+ namespaces are allocated in increasing order. After a
|
||||
+ namespace is initialized, r_brk becomes non-zero. A
|
||||
+ namespace becomes empty (r_map == NULL) when it is unused.
|
||||
+ But it is never removed from the linked list. */
|
||||
+
|
||||
+ if (ns != LM_ID_BASE)
|
||||
+ {
|
||||
+ r->base.r_version = 2;
|
||||
+ if (ns - 1 == LM_ID_BASE)
|
||||
+ {
|
||||
+ atomic_store_release (&_r_debug_extended.r_next, r);
|
||||
+ /* Now there are multiple namespaces. */
|
||||
+ atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||
+ }
|
||||
+ else
|
||||
+ /* Update r_debug_extended of the previous namespace. */
|
||||
+ atomic_store_release (&_r_debug_array[ns - 2].r_next, r);
|
||||
+ }
|
||||
+ else
|
||||
+#endif /* SHARED */
|
||||
+ r->base.r_version = 1;
|
||||
}
|
||||
|
||||
if (r->base.r_map == NULL)
|
||||
atomic_store_release (&r->base.r_map,
|
||||
(void *) GL(dl_ns)[ns]._ns_loaded);
|
||||
|
||||
- if (pp != NULL)
|
||||
- {
|
||||
- atomic_store_release (pp, r);
|
||||
- /* Bump r_version to 2 for the new namespace. */
|
||||
- atomic_store_release (&_r_debug_extended.base.r_version, 2);
|
||||
- }
|
||||
-
|
||||
return &r->base;
|
||||
}
|
||||
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index 695f3910234e87da..e09edb01da3b5b90 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -375,8 +375,6 @@ struct rtld_global
|
||||
size_t n_elements;
|
||||
void (*free) (void *);
|
||||
} _ns_unique_sym_table;
|
||||
- /* Keep track of changes to each namespace' list. */
|
||||
- struct r_debug_extended _ns_debug;
|
||||
} _dl_ns[DL_NNS];
|
||||
/* One higher than index of last used namespace. */
|
||||
EXTERN size_t _dl_nns;
|
||||
17
glibc-RHEL-47403-11.patch
Normal file
17
glibc-RHEL-47403-11.patch
Normal file
@ -0,0 +1,17 @@
|
||||
Downstream patch to keep ABI stable.
|
||||
Bring back a dummy `struct r_debug` member in `GL (dl_ns)`, to preserve
|
||||
`_rtld_global` layout.
|
||||
|
||||
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
|
||||
index e09edb01da3b5b90..3d9b90a22bfa6a7d 100644
|
||||
--- a/sysdeps/generic/ldsodefs.h
|
||||
+++ b/sysdeps/generic/ldsodefs.h
|
||||
@@ -375,6 +375,8 @@ struct rtld_global
|
||||
size_t n_elements;
|
||||
void (*free) (void *);
|
||||
} _ns_unique_sym_table;
|
||||
+ /* Dummy structure to keep the ABI stable. */
|
||||
+ struct r_debug _ns_debug_unused;
|
||||
} _dl_ns[DL_NNS];
|
||||
/* One higher than index of last used namespace. */
|
||||
EXTERN size_t _dl_nns;
|
||||
26
glibc-RHEL-47403-2.patch
Normal file
26
glibc-RHEL-47403-2.patch
Normal file
@ -0,0 +1,26 @@
|
||||
commit 7e84ac3a3ac9e7c4dc10de2ce65db971b9650e4d
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Sep 20 15:50:00 2021 +0200
|
||||
|
||||
elf: Include <sysdep.h> in elf/dl-debug-symbols.S
|
||||
|
||||
This is necessary to generate assembler marker sections on some
|
||||
targets.
|
||||
|
||||
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
|
||||
|
||||
diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S
|
||||
index b7e9f5d9470c4da2..28456ab1f237ea87 100644
|
||||
--- a/elf/dl-debug-symbols.S
|
||||
+++ b/elf/dl-debug-symbols.S
|
||||
@@ -18,6 +18,10 @@
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <rtld-sizes.h>
|
||||
+#include <sysdep.h>
|
||||
+
|
||||
+/* Some targets define a macro to denote the zero register. */
|
||||
+#undef zero
|
||||
|
||||
/* Define 2 symbols, _r_debug_extended and _r_debug, which is an alias
|
||||
of _r_debug_extended, but with the size of struct r_debug. */
|
||||
32
glibc-RHEL-47403-3.patch
Normal file
32
glibc-RHEL-47403-3.patch
Normal file
@ -0,0 +1,32 @@
|
||||
commit 1b5e65ef6a442fdccf88d43c3048f98292d85631
|
||||
Author: Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
Date: Sat Mar 25 21:27:01 2023 +0000
|
||||
|
||||
Minor: don't call _dl_debug_update (which can have side effects) inside assert
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index eef724f7e9b2211d..0d2b4cd4785a226a 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -596,7 +596,9 @@ dl_open_worker_begin (void *a)
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
add_to_global_update (new);
|
||||
|
||||
- assert (_dl_debug_update (args->nsid)->r_state == RT_CONSISTENT);
|
||||
+ const int r_state __attribute__ ((unused))
|
||||
+ = _dl_debug_update (args->nsid)->r_state;
|
||||
+ assert (r_state == RT_CONSISTENT);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -916,7 +918,9 @@ no more namespaces available for dlmopen()"));
|
||||
_dl_signal_exception (errcode, &exception, NULL);
|
||||
}
|
||||
|
||||
- assert (_dl_debug_update (args.nsid)->r_state == RT_CONSISTENT);
|
||||
+ const int r_state __attribute__ ((unused))
|
||||
+ = _dl_debug_update (args.nsid)->r_state;
|
||||
+ assert (r_state == RT_CONSISTENT);
|
||||
|
||||
/* Release the lock. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||
275
glibc-RHEL-47403-4.patch
Normal file
275
glibc-RHEL-47403-4.patch
Normal file
@ -0,0 +1,275 @@
|
||||
commit 9897ced8e78db5d813166a7ccccfd5a42c69ef20
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Oct 25 16:50:10 2024 +0200
|
||||
|
||||
elf: Run constructors on cyclic recursive dlopen (bug 31986)
|
||||
|
||||
This is conceptually similar to the reported bug, but does not
|
||||
depend on auditing. The fix is simple: just complete execution
|
||||
of the constructors. This exposed the fact that the link map
|
||||
for statically linked executables does not have l_init_called
|
||||
set, even though constructors have run.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile (fix local test re-ordering)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index b074cc29664b3e20..dc774b083eda202b 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -398,12 +398,15 @@ tests += \
|
||||
tst-dl-is_dso \
|
||||
tst-dlclose-lazy \
|
||||
tst-dlmodcount \
|
||||
- tst-dlmopen1 \
|
||||
- tst-dlmopen3 \
|
||||
- tst-dlmopen4 \
|
||||
tst-dlmopen-dlerror \
|
||||
tst-dlmopen-gethostbyname \
|
||||
tst-dlmopen-twice \
|
||||
+ tst-dlmopen1 \
|
||||
+ tst-dlmopen3 \
|
||||
+ tst-dlmopen4 \
|
||||
+ tst-dlopen-recurse \
|
||||
+ tst-dlopen-self \
|
||||
+ tst-dlopen-tlsmodid \
|
||||
tst-dlopen-tlsreinit1 \
|
||||
tst-dlopen-tlsreinit2 \
|
||||
tst-dlopen-tlsreinit3 \
|
||||
@@ -411,8 +414,6 @@ tests += \
|
||||
tst-dlopenfail \
|
||||
tst-dlopenfail-2 \
|
||||
tst-dlopenrpath \
|
||||
- tst-dlopen-self \
|
||||
- tst-dlopen-tlsmodid \
|
||||
tst-dlsym-error \
|
||||
tst-filterobj \
|
||||
tst-filterobj-dlopen \
|
||||
@@ -775,13 +776,15 @@ modules-names = \
|
||||
tst-deep1mod1 \
|
||||
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 \
|
||||
tst-dlmopen-twice-mod2 \
|
||||
+ tst-dlmopen1mod \
|
||||
+ tst-dlopen-recursemod1 \
|
||||
+ tst-dlopen-recursemod2 \
|
||||
tst-dlopen-sgid-mod \
|
||||
tst-dlopen-tlsreinitmod1 \
|
||||
tst-dlopen-tlsreinitmod2 \
|
||||
@@ -2856,6 +2859,9 @@ tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
|
||||
tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
|
||||
+$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
|
||||
+$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
|
||||
+
|
||||
LDFLAGS-tst-hash-collision1-mod.so = -Wl,--hash-style=both
|
||||
$(objpfx)tst-hash-collision1: $(objpfx)tst-hash-collision1-mod.so
|
||||
LDFLAGS-tst-hash-collision1-mod-gnu.so = -Wl,--hash-style=gnu
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 0d2b4cd4785a226a..0b0bfb8acda28caa 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -600,6 +600,14 @@ dl_open_worker_begin (void *a)
|
||||
= _dl_debug_update (args->nsid)->r_state;
|
||||
assert (r_state == RT_CONSISTENT);
|
||||
|
||||
+ /* Do not return without calling the (supposedly new) map's
|
||||
+ constructor. This case occurs if a dependency of a directly
|
||||
+ opened map has a constructor that calls dlopen again on the
|
||||
+ initially opened map. The new map is initialized last, so
|
||||
+ checking only it is enough. */
|
||||
+ if (!new->l_init_called)
|
||||
+ _dl_catch_exception (NULL, call_dl_init, args);
|
||||
+
|
||||
return;
|
||||
}
|
||||
|
||||
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||||
index 00abc2d8056c78b0..f4dc9c61a2637f8b 100644
|
||||
--- a/elf/dl-support.c
|
||||
+++ b/elf/dl-support.c
|
||||
@@ -103,6 +103,7 @@ static struct link_map _dl_main_map =
|
||||
.l_used = 1,
|
||||
.l_tls_offset = NO_TLS_OFFSET,
|
||||
.l_serial = 1,
|
||||
+ .l_init_called = 1,
|
||||
};
|
||||
|
||||
/* Namespace information. */
|
||||
diff --git a/elf/tst-dlopen-recurse.c b/elf/tst-dlopen-recurse.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..c7fb379d373c6e77
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-recurse.c
|
||||
@@ -0,0 +1,34 @@
|
||||
+/* Test that recursive dlopen runs constructors before return (bug 31986).
|
||||
+ Copyright (C) 2024 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 <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ void *handle = xdlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
|
||||
+ int *status = dlsym (handle, "recursemod1_status");
|
||||
+ printf ("info: recursemod1_status == %d (from main)\n", *status);
|
||||
+ TEST_COMPARE (*status, 2);
|
||||
+ xdlclose (handle);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-dlopen-recursemod1.c b/elf/tst-dlopen-recursemod1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..5e0cc0eb8c32d6d4
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-recursemod1.c
|
||||
@@ -0,0 +1,50 @@
|
||||
+/* Directly opened test module that gets recursively opened again.
|
||||
+ Copyright (C) 2024 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>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+int recursemod1_status;
|
||||
+
|
||||
+/* Force linking against st-dlopen-recursemod2.so. Also allows
|
||||
+ checking for relocation. */
|
||||
+extern int recursemod2_status;
|
||||
+int *force_recursemod2_reference = &recursemod2_status;
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ ++recursemod1_status;
|
||||
+ printf ("info: tst-dlopen-recursemod1.so constructor called (status %d)\n",
|
||||
+ recursemod1_status);
|
||||
+}
|
||||
+
|
||||
+static void __attribute__ ((destructor))
|
||||
+fini (void)
|
||||
+{
|
||||
+ /* The recursemod1_status variable was incremented in the
|
||||
+ tst-dlopen-recursemod2.so constructor. */
|
||||
+ printf ("info: tst-dlopen-recursemod1.so destructor called (status %d)\n",
|
||||
+ recursemod1_status);
|
||||
+ if (recursemod1_status != 2)
|
||||
+ {
|
||||
+ puts ("error: recursemod1_status == 2 expected");
|
||||
+ exit (1);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/elf/tst-dlopen-recursemod2.c b/elf/tst-dlopen-recursemod2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..edd2f2526b877810
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-recursemod2.c
|
||||
@@ -0,0 +1,66 @@
|
||||
+/* Indirectly opened module that recursively opens the directly opened module.
|
||||
+ Copyright (C) 2024 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 <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+int recursemod2_status;
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ ++recursemod2_status;
|
||||
+ printf ("info: tst-dlopen-recursemod2.so constructor called (status %d)\n",
|
||||
+ recursemod2_status);
|
||||
+ void *handle = dlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
|
||||
+ if (handle == NULL)
|
||||
+ {
|
||||
+ printf ("error: dlopen: %s\n", dlerror ());
|
||||
+ exit (1);
|
||||
+ }
|
||||
+ int *status = dlsym (handle, "recursemod1_status");
|
||||
+ if (status == NULL)
|
||||
+ {
|
||||
+ printf ("error: dlsym: %s\n", dlerror ());
|
||||
+ exit (1);
|
||||
+ }
|
||||
+ printf ("info: recursemod1_status == %d\n", *status);
|
||||
+ if (*status != 1)
|
||||
+ {
|
||||
+ puts ("error: recursemod1_status == 1 expected");
|
||||
+ exit (1);
|
||||
+ }
|
||||
+ ++*status;
|
||||
+ printf ("info: recursemod1_status == %d\n", *status);
|
||||
+
|
||||
+ int **mod2_status = dlsym (handle, "force_recursemod2_reference");
|
||||
+ if (mod2_status == NULL || *mod2_status != &recursemod2_status)
|
||||
+ {
|
||||
+ puts ("error: invalid recursemod2_status address in"
|
||||
+ " tst-dlopen-recursemod1.so");
|
||||
+ exit (1);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void __attribute__ ((destructor))
|
||||
+fini (void)
|
||||
+{
|
||||
+ printf ("info: tst-dlopen-recursemod2.so destructor called (status %d)\n",
|
||||
+ recursemod2_status);
|
||||
+}
|
||||
103
glibc-RHEL-47403-5.patch
Normal file
103
glibc-RHEL-47403-5.patch
Normal file
@ -0,0 +1,103 @@
|
||||
commit e096b7a1896886eb7dd2732ccbf1184b0eec9a63
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Oct 25 16:50:10 2024 +0200
|
||||
|
||||
elf: Signal LA_ACT_CONSISTENT to auditors after RT_CONSISTENT switch
|
||||
|
||||
Auditors can call into the dynamic loader again if
|
||||
LA_ACT_CONSISTENT, and those recursive calls could observe
|
||||
r_state != RT_CONSISTENT.
|
||||
|
||||
We should consider failing dlopen/dlmopen/dlclose if
|
||||
r_state != RT_CONSISTENT. The dynamic linker is probably not
|
||||
in a state in which it can handle reentrant calls. This
|
||||
needs further investigation.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
elf/rtld.c (kept SHARED guard downstream)
|
||||
|
||||
diff --git a/elf/dl-close.c b/elf/dl-close.c
|
||||
index bf699e58d753a1e2..8a4c3528a124d4e7 100644
|
||||
--- a/elf/dl-close.c
|
||||
+++ b/elf/dl-close.c
|
||||
@@ -759,6 +759,11 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
/* TLS is cleaned up for the unloaded modules. */
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
|
||||
|
||||
+ /* Notify the debugger those objects are finalized and gone. */
|
||||
+ r->r_state = RT_CONSISTENT;
|
||||
+ _dl_debug_state ();
|
||||
+ LIBC_PROBE (unmap_complete, 2, nsid, r);
|
||||
+
|
||||
#ifdef SHARED
|
||||
/* Auditing checkpoint: we have deleted all objects. Also, do not notify
|
||||
auditors of the cleanup of a failed audit module loading attempt. */
|
||||
@@ -771,11 +776,6 @@ _dl_close_worker (struct link_map *map, bool force)
|
||||
--GL(dl_nns);
|
||||
while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL);
|
||||
|
||||
- /* Notify the debugger those objects are finalized and gone. */
|
||||
- r->r_state = RT_CONSISTENT;
|
||||
- _dl_debug_state ();
|
||||
- LIBC_PROBE (unmap_complete, 2, nsid, r);
|
||||
-
|
||||
/* Recheck if we need to retry, release the lock. */
|
||||
out:
|
||||
if (dl_close_state == rerun)
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 0b0bfb8acda28caa..5095ea4f96b6cf49 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -638,17 +638,17 @@ dl_open_worker_begin (void *a)
|
||||
#endif
|
||||
}
|
||||
|
||||
-#ifdef SHARED
|
||||
- /* Auditing checkpoint: we have added all objects. */
|
||||
- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
|
||||
-#endif
|
||||
-
|
||||
/* Notify the debugger all new objects are now ready to go. */
|
||||
struct r_debug *r = _dl_debug_update (args->nsid);
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
LIBC_PROBE (map_complete, 3, args->nsid, r, new);
|
||||
|
||||
+#ifdef SHARED
|
||||
+ /* Auditing checkpoint: we have added all objects. */
|
||||
+ _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
|
||||
+#endif
|
||||
+
|
||||
_dl_open_check (new);
|
||||
|
||||
/* Print scope information. */
|
||||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||||
index 7d8ed0ac1188d527..cd233174c9d944b2 100644
|
||||
--- a/elf/rtld.c
|
||||
+++ b/elf/rtld.c
|
||||
@@ -2524,11 +2524,6 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
_dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */
|
||||
_dl_sysdep_start_cleanup ();
|
||||
|
||||
-#ifdef SHARED
|
||||
- /* Auditing checkpoint: we have added all objects. */
|
||||
- _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
|
||||
the address since by now the variable might be in another object. */
|
||||
r = _dl_debug_update (LM_ID_BASE);
|
||||
@@ -2536,6 +2531,11 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
_dl_debug_state ();
|
||||
LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
|
||||
|
||||
+#ifdef SHARED
|
||||
+ /* Auditing checkpoint: we have added all objects. */
|
||||
+ _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
|
||||
+#endif
|
||||
+
|
||||
#if defined USE_LDCONFIG && !defined MAP_COPY
|
||||
/* We must munmap() the cache file. */
|
||||
_dl_unload_cache ();
|
||||
342
glibc-RHEL-47403-6.patch
Normal file
342
glibc-RHEL-47403-6.patch
Normal file
@ -0,0 +1,342 @@
|
||||
commit 43db5e2c0672cae7edea7c9685b22317eae25471
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Oct 25 16:50:10 2024 +0200
|
||||
|
||||
elf: Signal RT_CONSISTENT after relocation processing in dlopen (bug 31986)
|
||||
|
||||
Previously, a la_activity audit event was generated before
|
||||
relocation processing completed. This does did not match what
|
||||
happened during initial startup in elf/rtld.c (towards the end
|
||||
of dl_main). It also caused various problems if an auditor
|
||||
tried to open the same shared object again using dlmopen:
|
||||
If it was the directly loaded object, it had a search scope
|
||||
associated with it, so the early exit in dl_open_worker_begin
|
||||
was taken even though the object was unrelocated. This caused
|
||||
the r_state == RT_CONSISTENT assert to fail. Avoidance of the
|
||||
assert also depends on reversing the order of r_state update
|
||||
and auditor event (already implemented in a previous commit).
|
||||
|
||||
At the later point, args->map can be NULL due to failure,
|
||||
so use the assigned namespace ID instead if that is available.
|
||||
|
||||
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile (fixup context)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index dc774b083eda202b..73deb69f5a3c9150 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -404,6 +404,7 @@ tests += \
|
||||
tst-dlmopen1 \
|
||||
tst-dlmopen3 \
|
||||
tst-dlmopen4 \
|
||||
+ tst-dlopen-auditdup \
|
||||
tst-dlopen-recurse \
|
||||
tst-dlopen-self \
|
||||
tst-dlopen-tlsmodid \
|
||||
@@ -783,6 +784,8 @@ modules-names = \
|
||||
tst-dlmopen-twice-mod1 \
|
||||
tst-dlmopen-twice-mod2 \
|
||||
tst-dlmopen1mod \
|
||||
+ tst-dlopen-auditdup-auditmod \
|
||||
+ tst-dlopen-auditdupmod \
|
||||
tst-dlopen-recursemod1 \
|
||||
tst-dlopen-recursemod2 \
|
||||
tst-dlopen-sgid-mod \
|
||||
@@ -2861,6 +2864,9 @@ tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
|
||||
$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
|
||||
$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
|
||||
+tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
|
||||
+$(objpfx)tst-dlopen-auditdup.out: \
|
||||
+ $(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
|
||||
|
||||
LDFLAGS-tst-hash-collision1-mod.so = -Wl,--hash-style=both
|
||||
$(objpfx)tst-hash-collision1: $(objpfx)tst-hash-collision1-mod.so
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 5095ea4f96b6cf49..6ec1ca033bbe7859 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -575,6 +575,14 @@ dl_open_worker_begin (void *a)
|
||||
_dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
|
||||
new->l_name, new->l_ns, new->l_direct_opencount);
|
||||
|
||||
+#ifdef SHARED
|
||||
+ /* No relocation processing on this execution path. But
|
||||
+ relocation has not been performed for static
|
||||
+ position-dependent executables, so disable the assert for
|
||||
+ static linking. */
|
||||
+ assert (new->l_relocated);
|
||||
+#endif
|
||||
+
|
||||
/* If the user requested the object to be in the global
|
||||
namespace but it is not so far, prepare to add it now. This
|
||||
can raise an exception to do a malloc failure. */
|
||||
@@ -596,10 +604,6 @@ dl_open_worker_begin (void *a)
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
add_to_global_update (new);
|
||||
|
||||
- const int r_state __attribute__ ((unused))
|
||||
- = _dl_debug_update (args->nsid)->r_state;
|
||||
- assert (r_state == RT_CONSISTENT);
|
||||
-
|
||||
/* Do not return without calling the (supposedly new) map's
|
||||
constructor. This case occurs if a dependency of a directly
|
||||
opened map has a constructor that calls dlopen again on the
|
||||
@@ -638,17 +642,6 @@ dl_open_worker_begin (void *a)
|
||||
#endif
|
||||
}
|
||||
|
||||
- /* Notify the debugger all new objects are now ready to go. */
|
||||
- struct r_debug *r = _dl_debug_update (args->nsid);
|
||||
- r->r_state = RT_CONSISTENT;
|
||||
- _dl_debug_state ();
|
||||
- LIBC_PROBE (map_complete, 3, args->nsid, r, new);
|
||||
-
|
||||
-#ifdef SHARED
|
||||
- /* Auditing checkpoint: we have added all objects. */
|
||||
- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT);
|
||||
-#endif
|
||||
-
|
||||
_dl_open_check (new);
|
||||
|
||||
/* Print scope information. */
|
||||
@@ -695,6 +688,7 @@ dl_open_worker_begin (void *a)
|
||||
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. */
|
||||
+ struct r_debug *r = _dl_debug_update (args->nsid);
|
||||
#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,
|
||||
@@ -782,6 +776,26 @@ dl_open_worker (void *a)
|
||||
|
||||
__rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
|
||||
|
||||
+ /* Auditing checkpoint and debugger signalling. Do this even on
|
||||
+ error, so that dlopen exists with consistent state. */
|
||||
+ if (args->nsid >= 0 || args->map != NULL)
|
||||
+ {
|
||||
+ Lmid_t nsid = args->map != NULL ? args->map->l_ns : args->nsid;
|
||||
+ struct r_debug *r = _dl_debug_update (nsid);
|
||||
+#ifdef SHARED
|
||||
+ bool was_not_consistent = r->r_state != RT_CONSISTENT;
|
||||
+#endif
|
||||
+ r->r_state = RT_CONSISTENT;
|
||||
+ _dl_debug_state ();
|
||||
+ LIBC_PROBE (map_complete, 3, nsid, r, new);
|
||||
+
|
||||
+#ifdef SHARED
|
||||
+ if (was_not_consistent)
|
||||
+ /* Avoid redudant/recursive signalling. */
|
||||
+ _dl_audit_activity_nsid (nsid, LA_ACT_CONSISTENT);
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
if (__glibc_unlikely (ex.errstring != NULL))
|
||||
/* Reraise the error. */
|
||||
_dl_signal_exception (err, &ex, NULL);
|
||||
diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..9b67295e94d03e7a
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-auditdup-auditmod.c
|
||||
@@ -0,0 +1,100 @@
|
||||
+/* Auditor that opens again an object that just has been opened.
|
||||
+ Copyright (C) 2024 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 <unistd.h>
|
||||
+
|
||||
+unsigned int
|
||||
+la_version (unsigned int v)
|
||||
+{
|
||||
+ return LAV_CURRENT;
|
||||
+}
|
||||
+
|
||||
+static bool trigger_on_la_activity;
|
||||
+
|
||||
+unsigned int
|
||||
+la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
|
||||
+{
|
||||
+ printf ("info: la_objopen: \"%s\"\n", map->l_name);
|
||||
+ if (strstr (map->l_name, "/tst-dlopen-auditdupmod.so") != NULL)
|
||||
+ trigger_on_la_activity = true;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+la_activity (uintptr_t *cookie, unsigned int flag)
|
||||
+{
|
||||
+ static unsigned int calls;
|
||||
+ ++calls;
|
||||
+ printf ("info: la_activity: call %u (flag %u)\n", calls, flag);
|
||||
+ fflush (stdout);
|
||||
+ if (trigger_on_la_activity)
|
||||
+ {
|
||||
+ /* Avoid triggering on the dlmopen call below. */
|
||||
+ static bool recursion;
|
||||
+ if (recursion)
|
||||
+ return;
|
||||
+ recursion = true;
|
||||
+
|
||||
+ puts ("info: about to dlmopen tst-dlopen-auditdupmod.so");
|
||||
+ fflush (stdout);
|
||||
+ void *handle = dlmopen (LM_ID_BASE, "tst-dlopen-auditdupmod.so",
|
||||
+ RTLD_NOW);
|
||||
+ if (handle == NULL)
|
||||
+ {
|
||||
+ printf ("error: dlmopen: %s\n", dlerror ());
|
||||
+ fflush (stdout);
|
||||
+ _exit (1);
|
||||
+ }
|
||||
+
|
||||
+ /* Check that the constructor has run. */
|
||||
+ int *status = dlsym (handle, "auditdupmod_status");
|
||||
+ if (status == NULL)
|
||||
+ {
|
||||
+ printf ("error: dlsym: %s\n", dlerror ());
|
||||
+ fflush (stdout);
|
||||
+ _exit (1);
|
||||
+ }
|
||||
+ printf ("info: auditdupmod_status == %d\n", *status);
|
||||
+ if (*status != 1)
|
||||
+ {
|
||||
+ puts ("error: auditdupmod_status == 1 expected");
|
||||
+ fflush (stdout);
|
||||
+ _exit (1);
|
||||
+ }
|
||||
+ /* Checked in the destructor and the main program. */
|
||||
+ ++*status;
|
||||
+ printf ("info: auditdupmod_status == %d\n", *status);
|
||||
+
|
||||
+ /* Check that the module has been relocated. */
|
||||
+ int **status_address = dlsym (handle, "auditdupmod_status_address");
|
||||
+ if (status_address == NULL || *status_address != status)
|
||||
+ {
|
||||
+ puts ("error: invalid auditdupmod_status address in"
|
||||
+ " tst-dlopen-auditdupmod.so");
|
||||
+ fflush (stdout);
|
||||
+ _exit (1);
|
||||
+ }
|
||||
+
|
||||
+ fflush (stdout);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/elf/tst-dlopen-auditdup.c b/elf/tst-dlopen-auditdup.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..d022c58ae3091da1
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-auditdup.c
|
||||
@@ -0,0 +1,36 @@
|
||||
+/* Test that recursive dlopen from auditor works (bug 31986).
|
||||
+ Copyright (C) 2024 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 <support/check.h>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ puts ("info: about to dlopen tst-dlopen-auditdupmod.so");
|
||||
+ fflush (stdout);
|
||||
+ void *handle = xdlopen ("tst-dlopen-auditdupmod.so", RTLD_NOW);
|
||||
+ int *status = xdlsym (handle, "auditdupmod_status");
|
||||
+ printf ("info: auditdupmod_status == %d (from main)\n", *status);
|
||||
+ TEST_COMPARE (*status, 2);
|
||||
+ xdlclose (handle);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-dlopen-auditdupmod.c b/elf/tst-dlopen-auditdupmod.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..59b7e21daa8212df
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-auditdupmod.c
|
||||
@@ -0,0 +1,48 @@
|
||||
+/* Directly opened test module that gets reopened from the auditor.
|
||||
+ Copyright (C) 2024 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>
|
||||
+#include <support/xdlfcn.h>
|
||||
+
|
||||
+int auditdupmod_status;
|
||||
+
|
||||
+/* Used to check for successful relocation processing. */
|
||||
+int *auditdupmod_status_address = &auditdupmod_status;
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ ++auditdupmod_status;
|
||||
+ printf ("info: tst-dlopen-auditdupmod.so constructor called (status %d)\n",
|
||||
+ auditdupmod_status);
|
||||
+}
|
||||
+
|
||||
+static void __attribute__ ((destructor))
|
||||
+fini (void)
|
||||
+{
|
||||
+ /* The tst-dlopen-auditdup-auditmod.so auditor incremented
|
||||
+ auditdupmod_status. */
|
||||
+ printf ("info: tst-dlopen-auditdupmod.so destructor called (status %d)\n",
|
||||
+ auditdupmod_status);
|
||||
+ if (auditdupmod_status != 2)
|
||||
+ {
|
||||
+ puts ("error: auditdupmod_status == 2 expected");
|
||||
+ exit (1);
|
||||
+ }
|
||||
+}
|
||||
272
glibc-RHEL-47403-7.patch
Normal file
272
glibc-RHEL-47403-7.patch
Normal file
@ -0,0 +1,272 @@
|
||||
commit 95129e6b8fabdaa8cd8a4a5cc20be0f4cb0ba59f
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Mon Oct 28 14:45:30 2024 +0100
|
||||
|
||||
Revert "elf: Run constructors on cyclic recursive dlopen (bug 31986)"
|
||||
|
||||
This reverts commit 9897ced8e78db5d813166a7ccccfd5a42c69ef20.
|
||||
|
||||
Adjust the test expectations in elf/tst-dlopen-auditdup-auditmod.c
|
||||
accordingly.
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile (fixup context)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index 73deb69f5a3c9150..a358ad7ff0eb2af7 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -405,7 +405,6 @@ tests += \
|
||||
tst-dlmopen3 \
|
||||
tst-dlmopen4 \
|
||||
tst-dlopen-auditdup \
|
||||
- tst-dlopen-recurse \
|
||||
tst-dlopen-self \
|
||||
tst-dlopen-tlsmodid \
|
||||
tst-dlopen-tlsreinit1 \
|
||||
@@ -786,8 +785,6 @@ modules-names = \
|
||||
tst-dlmopen1mod \
|
||||
tst-dlopen-auditdup-auditmod \
|
||||
tst-dlopen-auditdupmod \
|
||||
- tst-dlopen-recursemod1 \
|
||||
- tst-dlopen-recursemod2 \
|
||||
tst-dlopen-sgid-mod \
|
||||
tst-dlopen-tlsreinitmod1 \
|
||||
tst-dlopen-tlsreinitmod2 \
|
||||
@@ -2862,8 +2859,6 @@ tst-dlopen-tlsreinit3-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
$(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so
|
||||
tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
|
||||
|
||||
-$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so
|
||||
-$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so
|
||||
tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
|
||||
$(objpfx)tst-dlopen-auditdup.out: \
|
||||
$(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 6ec1ca033bbe7859..6557c2fd7ca0bbfe 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -604,14 +604,6 @@ dl_open_worker_begin (void *a)
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
add_to_global_update (new);
|
||||
|
||||
- /* Do not return without calling the (supposedly new) map's
|
||||
- constructor. This case occurs if a dependency of a directly
|
||||
- opened map has a constructor that calls dlopen again on the
|
||||
- initially opened map. The new map is initialized last, so
|
||||
- checking only it is enough. */
|
||||
- if (!new->l_init_called)
|
||||
- _dl_catch_exception (NULL, call_dl_init, args);
|
||||
-
|
||||
return;
|
||||
}
|
||||
|
||||
diff --git a/elf/dl-support.c b/elf/dl-support.c
|
||||
index f4dc9c61a2637f8b..00abc2d8056c78b0 100644
|
||||
--- a/elf/dl-support.c
|
||||
+++ b/elf/dl-support.c
|
||||
@@ -103,7 +103,6 @@ static struct link_map _dl_main_map =
|
||||
.l_used = 1,
|
||||
.l_tls_offset = NO_TLS_OFFSET,
|
||||
.l_serial = 1,
|
||||
- .l_init_called = 1,
|
||||
};
|
||||
|
||||
/* Namespace information. */
|
||||
diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c
|
||||
index 9b67295e94d03e7a..270a595ec4de1439 100644
|
||||
--- a/elf/tst-dlopen-auditdup-auditmod.c
|
||||
+++ b/elf/tst-dlopen-auditdup-auditmod.c
|
||||
@@ -66,7 +66,11 @@ la_activity (uintptr_t *cookie, unsigned int flag)
|
||||
_exit (1);
|
||||
}
|
||||
|
||||
- /* Check that the constructor has run. */
|
||||
+ /* Check that the constructor has not run. Running the
|
||||
+ constructor would require constructing its dependencies, but
|
||||
+ the constructor call that triggered this auditing activity
|
||||
+ has not completed, and constructors among the dependencies
|
||||
+ may not be able to deal with that. */
|
||||
int *status = dlsym (handle, "auditdupmod_status");
|
||||
if (status == NULL)
|
||||
{
|
||||
@@ -75,9 +79,9 @@ la_activity (uintptr_t *cookie, unsigned int flag)
|
||||
_exit (1);
|
||||
}
|
||||
printf ("info: auditdupmod_status == %d\n", *status);
|
||||
- if (*status != 1)
|
||||
+ if (*status != 0)
|
||||
{
|
||||
- puts ("error: auditdupmod_status == 1 expected");
|
||||
+ puts ("error: auditdupmod_status == 0 expected");
|
||||
fflush (stdout);
|
||||
_exit (1);
|
||||
}
|
||||
diff --git a/elf/tst-dlopen-recurse.c b/elf/tst-dlopen-recurse.c
|
||||
deleted file mode 100644
|
||||
index c7fb379d373c6e77..0000000000000000
|
||||
--- a/elf/tst-dlopen-recurse.c
|
||||
+++ /dev/null
|
||||
@@ -1,34 +0,0 @@
|
||||
-/* Test that recursive dlopen runs constructors before return (bug 31986).
|
||||
- Copyright (C) 2024 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 <support/check.h>
|
||||
-#include <support/xdlfcn.h>
|
||||
-
|
||||
-static int
|
||||
-do_test (void)
|
||||
-{
|
||||
- void *handle = xdlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
|
||||
- int *status = dlsym (handle, "recursemod1_status");
|
||||
- printf ("info: recursemod1_status == %d (from main)\n", *status);
|
||||
- TEST_COMPARE (*status, 2);
|
||||
- xdlclose (handle);
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-#include <support/test-driver.c>
|
||||
diff --git a/elf/tst-dlopen-recursemod1.c b/elf/tst-dlopen-recursemod1.c
|
||||
deleted file mode 100644
|
||||
index 5e0cc0eb8c32d6d4..0000000000000000
|
||||
--- a/elf/tst-dlopen-recursemod1.c
|
||||
+++ /dev/null
|
||||
@@ -1,50 +0,0 @@
|
||||
-/* Directly opened test module that gets recursively opened again.
|
||||
- Copyright (C) 2024 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>
|
||||
-#include <support/xdlfcn.h>
|
||||
-
|
||||
-int recursemod1_status;
|
||||
-
|
||||
-/* Force linking against st-dlopen-recursemod2.so. Also allows
|
||||
- checking for relocation. */
|
||||
-extern int recursemod2_status;
|
||||
-int *force_recursemod2_reference = &recursemod2_status;
|
||||
-
|
||||
-static void __attribute__ ((constructor))
|
||||
-init (void)
|
||||
-{
|
||||
- ++recursemod1_status;
|
||||
- printf ("info: tst-dlopen-recursemod1.so constructor called (status %d)\n",
|
||||
- recursemod1_status);
|
||||
-}
|
||||
-
|
||||
-static void __attribute__ ((destructor))
|
||||
-fini (void)
|
||||
-{
|
||||
- /* The recursemod1_status variable was incremented in the
|
||||
- tst-dlopen-recursemod2.so constructor. */
|
||||
- printf ("info: tst-dlopen-recursemod1.so destructor called (status %d)\n",
|
||||
- recursemod1_status);
|
||||
- if (recursemod1_status != 2)
|
||||
- {
|
||||
- puts ("error: recursemod1_status == 2 expected");
|
||||
- exit (1);
|
||||
- }
|
||||
-}
|
||||
diff --git a/elf/tst-dlopen-recursemod2.c b/elf/tst-dlopen-recursemod2.c
|
||||
deleted file mode 100644
|
||||
index edd2f2526b877810..0000000000000000
|
||||
--- a/elf/tst-dlopen-recursemod2.c
|
||||
+++ /dev/null
|
||||
@@ -1,66 +0,0 @@
|
||||
-/* Indirectly opened module that recursively opens the directly opened module.
|
||||
- Copyright (C) 2024 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 <stdio.h>
|
||||
-#include <stdlib.h>
|
||||
-
|
||||
-int recursemod2_status;
|
||||
-
|
||||
-static void __attribute__ ((constructor))
|
||||
-init (void)
|
||||
-{
|
||||
- ++recursemod2_status;
|
||||
- printf ("info: tst-dlopen-recursemod2.so constructor called (status %d)\n",
|
||||
- recursemod2_status);
|
||||
- void *handle = dlopen ("tst-dlopen-recursemod1.so", RTLD_NOW);
|
||||
- if (handle == NULL)
|
||||
- {
|
||||
- printf ("error: dlopen: %s\n", dlerror ());
|
||||
- exit (1);
|
||||
- }
|
||||
- int *status = dlsym (handle, "recursemod1_status");
|
||||
- if (status == NULL)
|
||||
- {
|
||||
- printf ("error: dlsym: %s\n", dlerror ());
|
||||
- exit (1);
|
||||
- }
|
||||
- printf ("info: recursemod1_status == %d\n", *status);
|
||||
- if (*status != 1)
|
||||
- {
|
||||
- puts ("error: recursemod1_status == 1 expected");
|
||||
- exit (1);
|
||||
- }
|
||||
- ++*status;
|
||||
- printf ("info: recursemod1_status == %d\n", *status);
|
||||
-
|
||||
- int **mod2_status = dlsym (handle, "force_recursemod2_reference");
|
||||
- if (mod2_status == NULL || *mod2_status != &recursemod2_status)
|
||||
- {
|
||||
- puts ("error: invalid recursemod2_status address in"
|
||||
- " tst-dlopen-recursemod1.so");
|
||||
- exit (1);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static void __attribute__ ((destructor))
|
||||
-fini (void)
|
||||
-{
|
||||
- printf ("info: tst-dlopen-recursemod2.so destructor called (status %d)\n",
|
||||
- recursemod2_status);
|
||||
-}
|
||||
218
glibc-RHEL-47403-8.patch
Normal file
218
glibc-RHEL-47403-8.patch
Normal file
@ -0,0 +1,218 @@
|
||||
commit d604f9c500570e80febfcc6a52b63a002b466f35
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Tue Mar 11 15:30:52 2025 +0100
|
||||
|
||||
elf: Test dlopen (NULL, RTLD_LAZY) from an ELF constructor
|
||||
|
||||
This call must not complete initialization of all shared objects
|
||||
in the global scope because the ELF constructor which makes the call
|
||||
likely has not finished initialization. Calling more constructors
|
||||
at this point would expose those to a partially constructed
|
||||
dependency.
|
||||
|
||||
This completes the revert of commit 9897ced8e78db5d813166a7ccccfd5a
|
||||
("elf: Run constructors on cyclic recursive dlopen (bug 31986)").
|
||||
|
||||
Conflicts:
|
||||
elf/Makefile (fixup context)
|
||||
|
||||
diff --git a/elf/Makefile b/elf/Makefile
|
||||
index a358ad7ff0eb2af7..3a50ca90366aec94 100644
|
||||
--- a/elf/Makefile
|
||||
+++ b/elf/Makefile
|
||||
@@ -405,6 +405,7 @@ tests += \
|
||||
tst-dlmopen3 \
|
||||
tst-dlmopen4 \
|
||||
tst-dlopen-auditdup \
|
||||
+ tst-dlopen-constructor-null \
|
||||
tst-dlopen-self \
|
||||
tst-dlopen-tlsmodid \
|
||||
tst-dlopen-tlsreinit1 \
|
||||
@@ -785,6 +786,8 @@ modules-names = \
|
||||
tst-dlmopen1mod \
|
||||
tst-dlopen-auditdup-auditmod \
|
||||
tst-dlopen-auditdupmod \
|
||||
+ tst-dlopen-constructor-null-mod1 \
|
||||
+ tst-dlopen-constructor-null-mod2 \
|
||||
tst-dlopen-sgid-mod \
|
||||
tst-dlopen-tlsreinitmod1 \
|
||||
tst-dlopen-tlsreinitmod2 \
|
||||
@@ -2937,3 +2940,9 @@ $(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o
|
||||
-Wl,--dynamic-linker=$(objpfx)ld.so
|
||||
$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so
|
||||
$< > $@ 2>&1; $(evaluate-test)
|
||||
+
|
||||
+$(objpfx)tst-dlopen-constructor-null: \
|
||||
+ $(objpfx)tst-dlopen-constructor-null-mod1.so \
|
||||
+ $(objpfx)tst-dlopen-constructor-null-mod2.so
|
||||
+$(objpfx)tst-dlopen-constructor-null-mod2.so: \
|
||||
+ $(objpfx)tst-dlopen-constructor-null-mod1.so
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index 6557c2fd7ca0bbfe..c225654822ee3520 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -604,6 +604,16 @@ dl_open_worker_begin (void *a)
|
||||
if ((mode & RTLD_GLOBAL) && new->l_global == 0)
|
||||
add_to_global_update (new);
|
||||
|
||||
+ /* It is not possible to run the ELF constructor for the new
|
||||
+ link map if it has not executed yet: If this dlopen call came
|
||||
+ from an ELF constructor that has not put that object into a
|
||||
+ consistent state, completing initialization for the entire
|
||||
+ scope will expose objects that have this partially
|
||||
+ constructed object among its dependencies to this
|
||||
+ inconsistent state. This could happen even with a benign
|
||||
+ dlopen (NULL, RTLD_LAZY) call from a constructor of an
|
||||
+ initially loaded shared object. */
|
||||
+
|
||||
return;
|
||||
}
|
||||
|
||||
diff --git a/elf/tst-dlopen-constructor-null-mod1.c b/elf/tst-dlopen-constructor-null-mod1.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..70a7a0ad46a1a666
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-constructor-null-mod1.c
|
||||
@@ -0,0 +1,55 @@
|
||||
+/* Module calling dlopen (NULL, RTLD_LAZY) to obtain the global scope.
|
||||
+ Copyright (C) 2024 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 <stddef.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+int mod1_status;
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ puts ("info: tst-dlopen-constructor-null-mod1.so constructor");
|
||||
+
|
||||
+ void *handle = dlopen (NULL, RTLD_LAZY);
|
||||
+ if (handle == NULL)
|
||||
+ {
|
||||
+ printf ("error: %s\n", dlerror ());
|
||||
+ exit (1);
|
||||
+ }
|
||||
+ puts ("info: dlopen returned");
|
||||
+ if (dlsym (handle, "malloc") != malloc)
|
||||
+ {
|
||||
+ puts ("error: dlsym did not produce expected result");
|
||||
+ exit (1);
|
||||
+ }
|
||||
+ dlclose (handle);
|
||||
+
|
||||
+ /* Check that the second module's constructor has not executed. */
|
||||
+ if (getenv ("mod2_status") != NULL)
|
||||
+ {
|
||||
+ printf ("error: mod2_status environment variable set: %s\n",
|
||||
+ getenv ("mod2_status"));
|
||||
+ exit (1);
|
||||
+ }
|
||||
+
|
||||
+ /* Communicate to the second module that the constructor executed. */
|
||||
+ mod1_status = 1;
|
||||
+}
|
||||
diff --git a/elf/tst-dlopen-constructor-null-mod2.c b/elf/tst-dlopen-constructor-null-mod2.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..d6e945beaec04815
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-constructor-null-mod2.c
|
||||
@@ -0,0 +1,37 @@
|
||||
+/* Module whose constructor should not be invoked by dlopen (NULL, RTLD_LAZY).
|
||||
+ Copyright (C) 2024 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>
|
||||
+
|
||||
+extern int mod1_status;
|
||||
+int mod2_status;
|
||||
+
|
||||
+static void __attribute__ ((constructor))
|
||||
+init (void)
|
||||
+{
|
||||
+ printf ("info: tst-dlopen-constructor-null-mod2.so constructor"
|
||||
+ " (mod1_status=%d)", mod1_status);
|
||||
+ if (!(mod1_status == 1 && mod2_status == 0))
|
||||
+ {
|
||||
+ puts ("error: mod1_status == 1 && mod2_status == 0 expected");
|
||||
+ exit (1);
|
||||
+ }
|
||||
+ setenv ("mod2_status", "constructed", 1);
|
||||
+ mod2_status = 1;
|
||||
+}
|
||||
diff --git a/elf/tst-dlopen-constructor-null.c b/elf/tst-dlopen-constructor-null.c
|
||||
new file mode 100644
|
||||
index 0000000000000000..db90643325c5235f
|
||||
--- /dev/null
|
||||
+++ b/elf/tst-dlopen-constructor-null.c
|
||||
@@ -0,0 +1,38 @@
|
||||
+/* Verify that dlopen (NULL, RTLD_LAZY) does not complete initialization.
|
||||
+ Copyright (C) 2024 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 mimics what the glvndSetupPthreads function in libglvnd
|
||||
+ does. */
|
||||
+
|
||||
+#include <stdlib.h>
|
||||
+#include <support/check.h>
|
||||
+
|
||||
+/* Defined and initialized in the shared objects. */
|
||||
+extern int mod1_status;
|
||||
+extern int mod2_status;
|
||||
+
|
||||
+static int
|
||||
+do_test (void)
|
||||
+{
|
||||
+ TEST_COMPARE (mod1_status, 1);
|
||||
+ TEST_COMPARE (mod2_status, 1);
|
||||
+ TEST_COMPARE_STRING (getenv ("mod2_status"), "constructed");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#include <support/test-driver.c>
|
||||
24
glibc-RHEL-47403-9.patch
Normal file
24
glibc-RHEL-47403-9.patch
Normal file
@ -0,0 +1,24 @@
|
||||
commit ac73067cb7a328bf106ecd041c020fc61be7e087
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
Date: Fri Oct 25 17:41:53 2024 +0200
|
||||
|
||||
elf: Fix map_complete Systemtap probe in dl_open_worker
|
||||
|
||||
The refactoring did not take the change of variable into account.
|
||||
Fixes commit 43db5e2c0672cae7edea7c9685b22317eae25471
|
||||
("elf: Signal RT_CONSISTENT after relocation processing in dlopen
|
||||
(bug 31986)").
|
||||
|
||||
diff --git a/elf/dl-open.c b/elf/dl-open.c
|
||||
index c225654822ee3520..1e61e402455da666 100644
|
||||
--- a/elf/dl-open.c
|
||||
+++ b/elf/dl-open.c
|
||||
@@ -789,7 +789,7 @@ dl_open_worker (void *a)
|
||||
#endif
|
||||
r->r_state = RT_CONSISTENT;
|
||||
_dl_debug_state ();
|
||||
- LIBC_PROBE (map_complete, 3, nsid, r, new);
|
||||
+ LIBC_PROBE (map_complete, 3, nsid, r, args->map);
|
||||
|
||||
#ifdef SHARED
|
||||
if (was_not_consistent)
|
||||
17
glibc.spec
17
glibc.spec
@ -157,7 +157,7 @@ end \
|
||||
Summary: The GNU libc libraries
|
||||
Name: glibc
|
||||
Version: %{glibcversion}
|
||||
Release: 211%{?dist}
|
||||
Release: 212%{?dist}
|
||||
|
||||
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
|
||||
# libraries.
|
||||
@ -1279,6 +1279,17 @@ Patch969: glibc-RHEL-24168-19.patch
|
||||
Patch970: glibc-RHEL-24168-20.patch
|
||||
Patch971: glibc-RHEL-24168-21.patch
|
||||
Patch972: glibc-RHEL-24168-22.patch
|
||||
Patch973: glibc-RHEL-47403-1.patch
|
||||
Patch974: glibc-RHEL-47403-2.patch
|
||||
Patch975: glibc-RHEL-47403-3.patch
|
||||
Patch976: glibc-RHEL-47403-4.patch
|
||||
Patch977: glibc-RHEL-47403-5.patch
|
||||
Patch978: glibc-RHEL-47403-6.patch
|
||||
Patch979: glibc-RHEL-47403-7.patch
|
||||
Patch980: glibc-RHEL-47403-8.patch
|
||||
Patch981: glibc-RHEL-47403-9.patch
|
||||
Patch982: glibc-RHEL-47403-10.patch
|
||||
Patch983: glibc-RHEL-47403-11.patch
|
||||
|
||||
##############################################################################
|
||||
# Continued list of core "glibc" package information:
|
||||
@ -3276,6 +3287,10 @@ update_gconv_modules_cache ()
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Tue Jul 08 2025 Frédéric Bérat <fberat@redhat.com> - 2.34-212
|
||||
- Prevented `ld.so` from asserting and crashing during audited library loads.
|
||||
(RHEL-47403)
|
||||
|
||||
* Tue Jul 08 2025 Arjun Shankar <arjun@redhat.com> - 2.34-211
|
||||
- Improve qsort implementation (RHEL-24168)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user