aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2021-06-03 08:26:04 +0200
committerFlorian Weimer <fweimer@redhat.com>2021-06-03 09:12:05 +0200
commit466c1ea15f461edb8e3ffaf5d86d708876343bbf (patch)
tree43d42d322ff24bd12c4124a9edafc4e0e4232f0a
parent9c76debc983e1a16e2e723b36526826713a671af (diff)
downloadglibc-466c1ea15f461edb8e3ffaf5d86d708876343bbf.zip
glibc-466c1ea15f461edb8e3ffaf5d86d708876343bbf.tar.gz
glibc-466c1ea15f461edb8e3ffaf5d86d708876343bbf.tar.bz2
dlfcn: Rework static dlopen hooks
Consolidate all hooks structures into a single one. There are no static dlopen ABI concerns because glibc 2.34 already comes with substantial ABI-incompatible changes in this area. (Static dlopen requires the exact same dynamic glibc version that was used for static linking.) The new approach uses a pointer to the hooks structure into _rtld_global_ro and initalizes it in __rtld_static_init. This avoids a back-and-forth with various callback functions. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
-rw-r--r--dlfcn/dladdr.c2
-rw-r--r--dlfcn/dladdr1.c2
-rw-r--r--dlfcn/dlclose.c2
-rw-r--r--dlfcn/dlerror.c32
-rw-r--r--dlfcn/dlinfo.c2
-rw-r--r--dlfcn/dlmopen.c10
-rw-r--r--dlfcn/dlopen.c10
-rw-r--r--dlfcn/dlopenold.c2
-rw-r--r--dlfcn/dlsym.c2
-rw-r--r--dlfcn/dlvsym.c3
-rw-r--r--elf/Versions1
-rw-r--r--elf/dl-libc.c73
-rw-r--r--elf/rtld_static_init.c18
-rw-r--r--include/dlfcn.h31
-rw-r--r--sysdeps/generic/ldsodefs.h3
15 files changed, 54 insertions, 139 deletions
diff --git a/dlfcn/dladdr.c b/dlfcn/dladdr.c
index 3ef1b7f..1cc305f 100644
--- a/dlfcn/dladdr.c
+++ b/dlfcn/dladdr.c
@@ -25,7 +25,7 @@ __dladdr (const void *address, Dl_info *info)
{
#ifdef SHARED
if (!rtld_active ())
- return _dlfcn_hook->dladdr (address, info);
+ return GLRO (dl_dlfcn_hook)->dladdr (address, info);
#endif
return _dl_addr (address, info, NULL, NULL);
}
diff --git a/dlfcn/dladdr1.c b/dlfcn/dladdr1.c
index 203d639..78560db 100644
--- a/dlfcn/dladdr1.c
+++ b/dlfcn/dladdr1.c
@@ -25,7 +25,7 @@ __dladdr1 (const void *address, Dl_info *info, void **extra, int flags)
{
#ifdef SHARED
if (!rtld_active ())
- return _dlfcn_hook->dladdr1 (address, info, extra, flags);
+ return GLRO (dl_dlfcn_hook)->dladdr1 (address, info, extra, flags);
#endif
switch (flags)
diff --git a/dlfcn/dlclose.c b/dlfcn/dlclose.c
index 4d5d307..6a013a8 100644
--- a/dlfcn/dlclose.c
+++ b/dlfcn/dlclose.c
@@ -25,7 +25,7 @@ __dlclose (void *handle)
{
#ifdef SHARED
if (!rtld_active ())
- return _dlfcn_hook->dlclose (handle);
+ return GLRO (dl_dlfcn_hook)->dlclose (handle);
#endif
return _dlerror_run (GLRO (dl_close), handle) ? -1 : 0;
diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
index 3df8602..d0194a7 100644
--- a/dlfcn/dlerror.c
+++ b/dlfcn/dlerror.c
@@ -33,7 +33,7 @@ __dlerror (void)
{
# ifdef SHARED
if (!rtld_active ())
- return _dlfcn_hook->dlerror ();
+ return GLRO (dl_dlfcn_hook)->dlerror ();
# endif
struct dl_action_result *result = __libc_dlerror_result;
@@ -197,33 +197,3 @@ _dlerror_run (void (*operate) (void *), void *args)
}
}
libc_hidden_def (_dlerror_run)
-
-#ifdef SHARED
-struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
-libc_hidden_data_def (_dlfcn_hook)
-
-#else /* !SHARED */
-
-static struct dlfcn_hook _dlfcn_hooks =
- {
- .dlopen = __dlopen,
- .dlclose = __dlclose,
- .dlsym = __dlsym,
- .dlvsym = __dlvsym,
- .dlerror = __dlerror,
- .dladdr = __dladdr,
- .dladdr1 = __dladdr1,
- .dlinfo = __dlinfo,
- .dlmopen = __dlmopen
- };
-
-void
-__libc_register_dlfcn_hook (struct link_map *map)
-{
- struct dlfcn_hook **hook;
-
- hook = (struct dlfcn_hook **) __libc_dlsym_private (map, "_dlfcn_hook");
- if (hook != NULL)
- *hook = &_dlfcn_hooks;
-}
-#endif /* !SHARED */
diff --git a/dlfcn/dlinfo.c b/dlfcn/dlinfo.c
index 15fcbc5..c6f9a1d 100644
--- a/dlfcn/dlinfo.c
+++ b/dlfcn/dlinfo.c
@@ -90,7 +90,7 @@ int
___dlinfo (void *handle, int request, void *arg)
{
if (!rtld_active ())
- return _dlfcn_hook->dlinfo (handle, request, arg);
+ return GLRO (dl_dlfcn_hook)->dlinfo (handle, request, arg);
else
return dlinfo_implementation (handle, request, arg);
}
diff --git a/dlfcn/dlmopen.c b/dlfcn/dlmopen.c
index ae42814..c171c89 100644
--- a/dlfcn/dlmopen.c
+++ b/dlfcn/dlmopen.c
@@ -81,7 +81,7 @@ void *
___dlmopen (Lmid_t nsid, const char *file, int mode)
{
if (!rtld_active ())
- return _dlfcn_hook->dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
+ return GLRO (dl_dlfcn_hook)->dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
else
return dlmopen_implementation (nsid, file, mode, RETURN_ADDRESS (0));
}
@@ -101,13 +101,7 @@ __dlmopen (Lmid_t nsid, const char *file, int mode, void *dl_caller)
void *
___dlmopen (Lmid_t nsid, const char *file, int mode)
{
- struct link_map *l = __dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
- if (l != NULL)
- {
- __libc_register_dl_open_hook (l);
- __libc_register_dlfcn_hook (l);
- }
- return l;
+ return __dlmopen (nsid, file, mode, RETURN_ADDRESS (0));
}
weak_alias (___dlmopen, dlmopen)
static_link_warning (dlmopen)
diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c
index afdc113..e04b374 100644
--- a/dlfcn/dlopen.c
+++ b/dlfcn/dlopen.c
@@ -76,7 +76,7 @@ void *
___dlopen (const char *file, int mode)
{
if (!rtld_active ())
- return _dlfcn_hook->dlopen (file, mode, RETURN_ADDRESS (0));
+ return GLRO (dl_dlfcn_hook)->dlopen (file, mode, RETURN_ADDRESS (0));
else
return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
}
@@ -96,13 +96,7 @@ __dlopen (const char *file, int mode, void *dl_caller)
void *
___dlopen (const char *file, int mode)
{
- struct link_map *l = __dlopen (file, mode, RETURN_ADDRESS (0));
- if (l != NULL)
- {
- __libc_register_dl_open_hook (l);
- __libc_register_dlfcn_hook (l);
- }
- return l;
+ return __dlopen (file, mode, RETURN_ADDRESS (0));
}
weak_alias (___dlopen, dlopen)
static_link_warning (dlopen)
diff --git a/dlfcn/dlopenold.c b/dlfcn/dlopenold.c
index 0fe5f24..9115501 100644
--- a/dlfcn/dlopenold.c
+++ b/dlfcn/dlopenold.c
@@ -71,7 +71,7 @@ __dlopen_nocheck (const char *file, int mode)
args.mode = mode;
if (!rtld_active ())
- return _dlfcn_hook->dlopen (file, mode, RETURN_ADDRESS (0));
+ return GLRO (dl_dlfcn_hook)->dlopen (file, mode, RETURN_ADDRESS (0));
return _dlerror_run (dlopen_doit, &args) ? NULL : args.new;
}
diff --git a/dlfcn/dlsym.c b/dlfcn/dlsym.c
index 6b03b7b..43044cf 100644
--- a/dlfcn/dlsym.c
+++ b/dlfcn/dlsym.c
@@ -63,7 +63,7 @@ void *
___dlsym (void *handle, const char *name)
{
if (!rtld_active ())
- return _dlfcn_hook->dlsym (handle, name, RETURN_ADDRESS (0));
+ return GLRO (dl_dlfcn_hook)->dlsym (handle, name, RETURN_ADDRESS (0));
else
return dlsym_implementation (handle, name, RETURN_ADDRESS (0));
}
diff --git a/dlfcn/dlvsym.c b/dlfcn/dlvsym.c
index de6b340..9b76f9a 100644
--- a/dlfcn/dlvsym.c
+++ b/dlfcn/dlvsym.c
@@ -66,7 +66,8 @@ void *
___dlvsym (void *handle, const char *name, const char *version)
{
if (!rtld_active ())
- return _dlfcn_hook->dlvsym (handle, name, version, RETURN_ADDRESS (0));
+ return GLRO (dl_dlfcn_hook)->dlvsym (handle, name, version,
+ RETURN_ADDRESS (0));
else
return dlvsym_implementation (handle, name, version, RETURN_ADDRESS (0));
}
diff --git a/elf/Versions b/elf/Versions
index be88c48..a12d64e 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -23,7 +23,6 @@ libc {
GLIBC_PRIVATE {
# functions used in other libraries
_dl_addr;
- _dl_open_hook; _dl_open_hook2;
_dl_sym; _dl_vsym;
__libc_dlclose; __libc_dlopen_mode; __libc_dlsym; __libc_dlvsym;
__libc_early_init;
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index ed551f6..8e0734f 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -126,32 +126,7 @@ do_dlclose (void *ptr)
GLRO(dl_close) ((struct link_map *) ptr);
}
-/* This code is to support __libc_dlopen from __libc_dlopen'ed shared
- libraries. We need to ensure the statically linked __libc_dlopen
- etc. functions are used instead of the dynamically loaded. */
-struct dl_open_hook
-{
- void *(*dlopen_mode) (const char *name, int mode);
- void *(*dlsym) (void *map, const char *name);
- int (*dlclose) (void *map);
- void *(*dlvsym) (void *map, const char *name, const char *version);
-};
-
-#ifdef SHARED
-extern struct dl_open_hook *_dl_open_hook;
-libc_hidden_proto (_dl_open_hook);
-struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
-libc_hidden_data_def (_dl_open_hook);
-
-/* The dlvsym member was added retroactively to struct dl_open_hook.
- Static applications which have it will set _dl_open_hook2 in
- addition to _dl_open_hook. */
-extern struct dl_open_hook *_dl_open_hook2;
-libc_hidden_proto (_dl_open_hook2);
-struct dl_open_hook *_dl_open_hook2 __attribute__ ((nocommon));
-libc_hidden_data_def (_dl_open_hook2);
-
-#else
+#ifndef SHARED
static void
do_dlsym_private (void *ptr)
{
@@ -169,14 +144,6 @@ do_dlsym_private (void *ptr)
args->map->l_scope, &vers, 0, 0, NULL);
args->loadbase = l;
}
-
-static struct dl_open_hook _dl_open_hook =
- {
- .dlopen_mode = __libc_dlopen_mode,
- .dlsym = __libc_dlsym,
- .dlclose = __libc_dlclose,
- .dlvsym = __libc_dlvsym,
- };
#endif
/* ... and these functions call dlerror_run. */
@@ -191,16 +158,9 @@ __libc_dlopen_mode (const char *name, int mode)
#ifdef SHARED
if (!rtld_active ())
- return _dl_open_hook->dlopen_mode (name, mode);
- return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map);
-#else
- if (dlerror_run (do_dlopen, &args))
- return NULL;
-
- __libc_register_dl_open_hook (args.map);
- __libc_register_dlfcn_hook (args.map);
- return (void *) args.map;
+ return GLRO (dl_dlfcn_hook)->libc_dlopen_mode (name, mode);
#endif
+ return dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map;
}
libc_hidden_def (__libc_dlopen_mode)
@@ -216,21 +176,6 @@ __libc_dlsym_private (struct link_map *map, const char *name)
return DL_SYMBOL_ADDRESS (sargs.loadbase, sargs.ref);
return NULL;
}
-
-void
-__libc_register_dl_open_hook (struct link_map *map)
-{
- struct dl_open_hook **hook;
-
- hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook");
- if (hook != NULL)
- *hook = &_dl_open_hook;
-
- /* For dlvsym support. */
- hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook2");
- if (hook != NULL)
- *hook = &_dl_open_hook;
-}
#endif
void *
@@ -242,7 +187,7 @@ __libc_dlsym (void *map, const char *name)
#ifdef SHARED
if (!rtld_active ())
- return _dl_open_hook->dlsym (map, name);
+ return GLRO (dl_dlfcn_hook)->libc_dlsym (map, name);
#endif
return (dlerror_run (do_dlsym, &args) ? NULL
: (void *) (DL_SYMBOL_ADDRESS (args.loadbase, args.ref)));
@@ -257,13 +202,7 @@ __libc_dlvsym (void *map, const char *name, const char *version)
{
#ifdef SHARED
if (!rtld_active ())
- {
- /* The static application is too old and does not provide the
- dlvsym hook. */
- if (_dl_open_hook2 == NULL)
- return NULL;
- return _dl_open_hook2->dlvsym (map, name, version);
- }
+ return GLRO (dl_dlfcn_hook)->libc_dlvsym (map, name, version);
#endif
struct do_dlvsym_args args;
@@ -287,7 +226,7 @@ __libc_dlclose (void *map)
{
#ifdef SHARED
if (!rtld_active ())
- return _dl_open_hook->dlclose (map);
+ return GLRO (dl_dlfcn_hook)->libc_dlclose (map);
#endif
return dlerror_run (do_dlclose, map);
}
diff --git a/elf/rtld_static_init.c b/elf/rtld_static_init.c
index 42efecf..3f8abb6 100644
--- a/elf/rtld_static_init.c
+++ b/elf/rtld_static_init.c
@@ -25,6 +25,23 @@
#include <rtld_static_init.h>
+static const struct dlfcn_hook _dlfcn_hook =
+ {
+ .dlopen = __dlopen,
+ .dlclose = __dlclose,
+ .dlsym = __dlsym,
+ .dlvsym = __dlvsym,
+ .dlerror = __dlerror,
+ .dladdr = __dladdr,
+ .dladdr1 = __dladdr1,
+ .dlinfo = __dlinfo,
+ .dlmopen = __dlmopen,
+ .libc_dlopen_mode = __libc_dlopen_mode,
+ .libc_dlsym = __libc_dlsym,
+ .libc_dlvsym = __libc_dlvsym,
+ .libc_dlclose = __libc_dlclose,
+ };
+
void
__rtld_static_init (struct link_map *map)
{
@@ -45,6 +62,7 @@ __rtld_static_init (struct link_map *map)
extern __typeof (dl->_dl_clktck) _dl_clktck attribute_hidden;
dl->_dl_clktck = _dl_clktck;
#endif
+ dl->_dl_dlfcn_hook = &_dlfcn_hook;
extern __typeof (dl->_dl_hwcap) _dl_hwcap attribute_hidden;
dl->_dl_hwcap = _dl_hwcap;
extern __typeof (dl->_dl_hwcap2) _dl_hwcap2 attribute_hidden;
diff --git a/include/dlfcn.h b/include/dlfcn.h
index 711bbb0..d4440c5 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -91,8 +91,12 @@ libc_hidden_proto (_dl_vsym)
extern int _dlerror_run (void (*operate) (void *), void *args);
libc_hidden_proto (_dlerror_run)
+/* This structure is used to make the outer (statically linked)
+ implementation of dlopen and related functions to the inner libc
+ after static dlopen, via the GLRO (dl_dlfcn_hook) pointer. */
struct dlfcn_hook
{
+ /* Public interfaces. */
void *(*dlopen) (const char *file, int mode, void *dl_caller);
int (*dlclose) (void *handle);
void *(*dlsym) (void *handle, const char *name, void *dl_caller);
@@ -104,15 +108,17 @@ struct dlfcn_hook
void **extra_info, int flags);
int (*dlinfo) (void *handle, int request, void *arg);
void *(*dlmopen) (Lmid_t nsid, const char *file, int mode, void *dl_caller);
- void *pad[4];
-};
-extern struct dlfcn_hook *_dlfcn_hook;
-libc_hidden_proto (_dlfcn_hook)
+ /* Internal interfaces. */
+ void* (*libc_dlopen_mode) (const char *__name, int __mode);
+ void* (*libc_dlsym) (void *map, const char *name);
+ void* (*libc_dlvsym) (void *map, const char *name, const char *version);
+ int (*libc_dlclose) (void *map);
+};
-/* Note: These prototypes are for initializing _dflcn_hook in static
- libraries. Internal calls in glibc should use the __libc_dl*
- functions defined in elf/dl-libc.c instead. */
+/* Note: These prototypes are for initializing _dlfcn_hook in static
+ builds; see __rtld_static_init. Internal calls in glibc should use
+ the __libc_dl* functions defined in elf/dl-libc.c instead. */
extern void *__dlopen (const char *file, int mode, void *caller);
extern void *__dlmopen (Lmid_t nsid, const char *file, int mode,
@@ -125,16 +131,7 @@ extern int __dladdr (const void *address, Dl_info *info);
extern int __dladdr1 (const void *address, Dl_info *info,
void **extra_info, int flags);
extern int __dlinfo (void *handle, int request, void *arg);
-
-#ifndef SHARED
-struct link_map;
-extern void * __libc_dlsym_private (struct link_map *map, const char *name)
- attribute_hidden;
-extern void __libc_register_dl_open_hook (struct link_map *map)
- attribute_hidden;
-extern void __libc_register_dlfcn_hook (struct link_map *map)
- attribute_hidden;
-#endif
+extern char *__dlerror (void);
#endif
#endif
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index e383aa1..176394d 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -687,6 +687,9 @@ struct rtld_global_ro
int (*_dl_discover_osversion) (void);
#endif
+ /* Dynamic linker operations used after static dlopen. */
+ const struct dlfcn_hook *_dl_dlfcn_hook;
+
/* List of auditing interfaces. */
struct audit_ifaces *_dl_audit;
unsigned int _dl_naudit;