Increase robustness of internal dlopen() by using RTLD_NOW [BZ #22766]

Prevent random runtime crashes due to missing symbols caused by mixed
libnss_* versions.

	[BZ #22766]
	* include/dlfcn.h [__libc_dl_open]: Replace RTLD_LAZY with RTLD_NOW.
	* sysdeps/gnu/unwind-resume.c (__lib_gcc_s_init): Replace
	__libc_dlopen_mode() using RTLD_NOW with __libc_dlopen.
	* sysdeps/nptl/unwind-forcedunwind.c: Likewise.

Signed-off-by: Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Tulio Magno Quites Machado Filho 2018-04-26 10:41:43 -03:00
parent 7d80f48e93
commit 81b49e9692
4 changed files with 34 additions and 7 deletions

View File

@ -1,3 +1,11 @@
2018-04-26 Tulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
[BZ #22766]
* include/dlfcn.h [__libc_dl_open]: Replace RTLD_LAZY with RTLD_NOW.
* sysdeps/gnu/unwind-resume.c (__lib_gcc_s_init): Replace
__libc_dlopen_mode() using RTLD_NOW with __libc_dlopen.
* sysdeps/nptl/unwind-forcedunwind.c: Likewise.
2018-04-25 Adhemerval Zanella <adhemerval.zanella@linaro.org>
* sysdeps/unix/sysv/linux/getdirentries.c (getdirentries): Build iff

View File

@ -31,8 +31,29 @@ extern char **__libc_argv attribute_hidden;
/* Now define the internal interfaces. */
/* Use RTLD_NOW here because:
1. In pthread_cancel_init we want to use RTLD_NOW to reduce the stack usage
of future cancellation operations, particularly when the target thread
is running with a small stack. Likewise for consistency we do the same
thing in __libgcc_s_init. RTLD_NOW will rarely make a difference for
__libgcc_s_init because unwinding is already in progress, so libgcc_s.so
has already been loaded if its unwinder is used (Bug 22636).
2. It allows us to provide robust fallback code at dlopen time for
incorrectly configured systems that mix old libnss_* modules with newly
installed libraries e.g. old libnss_nis.so.2 with new libnsl.so.1. Using
RTLD_LAZY here causes a failure at the time the symbol is called and at
that point it is much harder to safely return an error (Bug 22766).
The use of RTLD_NOW also impacts gconv module loading, backtracing
(where the unwinder form libgcc_s.so is used), and IDNA functions
(which load libidn), all of which load their respective DSOs on
demand, and so should not impact program startup. That is to say
that the DSOs are loaded as part of an API call and therefore we
will be calling that family of API functions shortly so RTLD_NOW or
RTLD_LAZY is not a big difference in performance, but RTLD_NOW has
better error handling semantics for the library. */
#define __libc_dlopen(name) \
__libc_dlopen_mode (name, RTLD_LAZY | __RTLD_DLOPEN)
__libc_dlopen_mode (name, RTLD_NOW | __RTLD_DLOPEN)
extern void *__libc_dlopen_mode (const char *__name, int __mode);
extern void *__libc_dlsym (void *__map, const char *__name);
extern void *__libc_dlvsym (void *map, const char *name, const char *version);

View File

@ -35,11 +35,8 @@ __libgcc_s_init (void)
void *resume, *personality;
void *handle;
/* Use RTLD_NOW here for consistency with pthread_cancel_init.
RTLD_NOW will rarely make a difference here because unwinding is
already in progress, so libgcc_s.so has already been loaded if
its unwinder is used. */
handle = __libc_dlopen_mode (LIBGCC_S_SO, RTLD_NOW | __RTLD_DLOPEN);
/* See include/dlfcn.h. Use of __libc_dlopen requires RTLD_NOW. */
handle = __libc_dlopen (LIBGCC_S_SO);
if (handle == NULL
|| (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL

View File

@ -49,7 +49,8 @@ pthread_cancel_init (void)
return;
}
handle = __libc_dlopen_mode (LIBGCC_S_SO, RTLD_NOW | __RTLD_DLOPEN);
/* See include/dlfcn.h. Use of __libc_dlopen requires RTLD_NOW. */
handle = __libc_dlopen (LIBGCC_S_SO);
if (handle == NULL
|| (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL