rtld: ignore static TLS segments when tracing.

For PIE binaries, ldd(1) performs dlopen(RTLD_TRACE) on the binary.
It is legal for binary to use initial exec TLS mode, but when such
binary (actually dso) is dlopened, we might not have enough free space
in the finalized static TLS segment.  Make ldd operational by skipping
TLS space allocation, we are not going to execute any code from the
dso anyway.

Reported by:	tobik
PR:	245677
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2020-04-22 18:39:45 +00:00
parent d2187b39cf
commit 62af2dc3fb
2 changed files with 5 additions and 4 deletions

View File

@ -3367,7 +3367,7 @@ rtld_dlopen(const char *name, int fd, int mode)
if (mode & RTLD_NOLOAD)
lo_flags |= RTLD_LO_NOLOAD;
if (ld_tracing != NULL)
lo_flags |= RTLD_LO_TRACE;
lo_flags |= RTLD_LO_TRACE | RTLD_LO_IGNSTLS;
return (dlopen_object(name, fd, obj_main, lo_flags,
mode & (RTLD_MODEMASK | RTLD_GLOBAL), NULL));
@ -3418,15 +3418,15 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags,
/* We loaded something new. */
assert(globallist_next(old_obj_tail) == obj);
result = 0;
if ((lo_flags & RTLD_LO_EARLY) == 0 && obj->static_tls &&
!allocate_tls_offset(obj)) {
if ((lo_flags & (RTLD_LO_EARLY | RTLD_LO_IGNSTLS)) == 0 &&
obj->static_tls && !allocate_tls_offset(obj)) {
_rtld_error("%s: No space available "
"for static Thread Local Storage", obj->path);
result = -1;
}
if (result != -1)
result = load_needed_objects(obj, lo_flags & (RTLD_LO_DLOPEN |
RTLD_LO_EARLY));
RTLD_LO_EARLY | RTLD_LO_IGNSTLS));
init_dag(obj);
ref_dag(obj);
if (result != -1)

View File

@ -308,6 +308,7 @@ TAILQ_HEAD(obj_entry_q, Struct_Obj_Entry);
#define RTLD_LO_FILTEES 0x10 /* Loading filtee. */
#define RTLD_LO_EARLY 0x20 /* Do not call ctors, postpone it to the
initialization during the image start. */
#define RTLD_LO_IGNSTLS 0x40 /* Do not allocate static TLS */
/*
* Symbol cache entry used during relocation to avoid multiple lookups