about summary refs log tree commit diff
path: root/src/ldso/dynlink.c
Commit message (Collapse)AuthorAgeFilesLines
* remove lazy ssp initializationTimo Teräs2014-03-251-13/+0
| | | | | | | | now that thread pointer is initialized always, ssp canary initialization can be done unconditionally. this simplifies the ldso as it does not try to detect ssp usage, and the init function itself as it is always called exactly once. this also merges ssp init path for shared and static linking.
* if dynamic linker's relro mprotect call fails, include reason in messageRich Felker2014-03-251-1/+1
|
* cosmetic improvements in dynamic linker cleanupRich Felker2014-03-251-5/+5
| | | | consistent use of braces in if/else structure, line length.
* clean up internal dynamic linker functions enumerating phdrsTimo Teräs2014-03-251-28/+23
| | | | | | | | record phentsize in struct dso, so the phdrs can be easily enumerated via it. simplify all functions enumerating phdrs to require only struct dso. also merge find_map_range and find_dso to kernel_mapped_dso function that does both tasks during single phdr enumeration.
* implement PT_GNU_RELRO supportTimo Teräs2014-03-251-15/+37
|
* always initialize thread pointer at program startRich Felker2014-03-241-9/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | this is the first step in an overhaul aimed at greatly simplifying and optimizing everything dealing with thread-local state. previously, the thread pointer was initialized lazily on first access, or at program startup if stack protector was in use, or at certain random places where inconsistent state could be reached if it were not initialized early. while believed to be fully correct, the logic was fragile and non-obvious. in the first phase of the thread pointer overhaul, support is retained (and in some cases improved) for systems/situation where loading the thread pointer fails, e.g. old kernels. some notes on specific changes: - the confusing use of libc.main_thread as an indicator that the thread pointer is initialized is eliminated in favor of an explicit has_thread_pointer predicate. - sigaction no longer needs to ensure that the thread pointer is initialized before installing a signal handler (this was needed to prevent a situation where the signal handler caused the thread pointer to be initialized and the subsequent sigreturn cleared it again) but it still needs to ensure that implementation-internal thread-related signals are not blocked. - pthread tsd initialization for the main thread is deferred in a new manner to minimize bloat in the static-linked __init_tp code. - pthread_setcancelstate no longer needs special handling for the situation before the thread pointer is initialized. it simply fails on systems that cannot support a thread pointer, which are non-conforming anyway. - pthread_cleanup_push/pop now check for missing thread pointer and nop themselves out in this case, so stdio no longer needs to avoid the cancellable path when the thread pointer is not available. a number of cases remain where certain interfaces may crash if the system does not support a thread pointer. at this point, these should be limited to pthread interfaces, and the number of such cases should be fewer than before.
* fix crash in dynamic linker when certain copy relocations are unsatisfiedRich Felker2014-01-211-1/+2
| | | | | | | | | | | | | | | | | | | | | STB_WEAK is only a weak reference for undefined symbols (those with a section of SHN_UNDEF). otherwise, it's a weak definition. normally this distinction would not matter, since a relocation referencing a symbol that also provides a definition (not SHN_UNDEF) will always succeed in finding the referenced symbol itself. however, in the case of copy relocations, the referenced symbol itself is ignored in order to search for another symbol to copy from, and thus it's possible that no definition is found. in this case, if the symbol being resolved happened to be a weak definition, it was misinterpreted as a weak reference, suppressing the error path and causing a crash when the copy relocation was performed with a null source pointer passed to memcpy. there are almost certainly still situations in which invalid combinations of symbol and relocation types can cause the dynamic linker to crash (this is pretty much inevitable), but the intent is that crashes not be possible for symbol/relocation tables produced by a valid linker.
* const-qualify the address argument to dladdrRich Felker2014-01-061-2/+2
| | | | | | | this agrees with implementation practice on glibc and BSD systems, and is the const-correct way to do things; it eliminates warnings from passing pointers to const. the prototype without const came from seemingly erroneous man pages.
* add infrastructure to record and report the version of libc.soRich Felker2013-12-011-2/+7
| | | | | | | this is still experimental and subject to change. for git checkouts, an attempt is made to record the exact revision to aid in bug reports and debugging. no version information is recorded in the static libc.a or binaries it's linked into.
* remove duplicate includes from dynlink.c, strfmon.c and getaddrinfo.cSzabolcs Nagy2013-11-251-3/+0
|
* fix uninitialized variable in dladdrRich Felker2013-10-041-1/+1
| | | | | the affected branch only applies for DSOs that lack standard hash table and only have the GNU hash table present.
* support configurable page size on mips, powerpc and microblazeSzabolcs Nagy2013-09-151-0/+1
| | | | | | | | | | | | | | | | PAGE_SIZE was hardcoded to 4096, which is historically what most systems use, but on several archs it is a kernel config parameter, user space can only know it at execution time from the aux vector. PAGE_SIZE and PAGESIZE are not defined on archs where page size is a runtime parameter, applications should use sysconf(_SC_PAGE_SIZE) to query it. Internally libc code defines PAGE_SIZE to libc.page_size, which is set to aux[AT_PAGESZ] in __init_libc and early in __dynlink as well. (Note that libc.page_size can be accessed without GOT, ie. before relocations are done) Some fpathconf settings are hardcoded to 4096, these should be actually queried from the filesystem using statfs.
* do not use default when dynamic linker fails to open existing path fileRich Felker2013-09-091-0/+2
| | | | | | | | if fopen fails for a reason other than ENOENT, we must assume the intent is that the path file be used. failure may be due to misconfiguration or intentional resource-exhaustion attack (against suid programs), in which case falling back to loading libraries from an unintended path could be dangerous.
* make dlopen honor the rpath of the main programRich Felker2013-08-231-1/+1
| | | | | | this seems to match what other systems do, and seems useful for programs that have their libraries and plugins stored relative to the executable.
* fix bugs in $ORIGIN handlingRich Felker2013-08-231-3/+9
| | | | | | | | 1. an occurrence of ${ORIGIN} before $ORIGIN would be ignored due to the strstr logic. (note that rpath contains multiple :-delimited paths to be searched.) 2. data read by readlink was not null-terminated.
* use AT_EXECFN, if available, for dynamic linker to identify main programRich Felker2013-08-231-1/+5
| | | | | | | | | | fallback to argv[0] as before. unlike argv[0], AT_EXECFN was a valid (but possibly relative) pathname for the new program image at the time the execve syscall was made. as a special case, ignore AT_EXECFN if it begins with "/proc/", in order not to give bogus (and possibly harmful) results when fexecve was used.
* add rpath $ORIGIN processing to dynamic linkerRich Felker2013-08-231-3/+59
|
* add recursive rpath support to dynamic linkerRich Felker2013-08-231-12/+13
| | | | | | | | | | previously, rpath was only honored for direct dependencies. in other words, if A depends on B and B depends on C, only B's rpath (if any), not A's rpath, was being searched for C. this limitation made rpath-based deployment difficult in the presence of multiple levels of library dependency. at present, $ORIGIN processing in rpath is still unsupported.
* work around libraries with versioned symbols in dynamic linkerRich Felker2013-08-081-11/+14
| | | | | | | | | | | | | | | | this commit does not add versioning support; it merely fixes incorrect lookups of symbols in libraries that contain versioned symbols. previously, the version information was completely ignored, and empirically this seems to have resulted in the oldest version being chosen, but I am uncertain if that behavior was even reliable. the new behavior being introduced is to completely ignore symbols which are marked "hidden" (this seems to be the confusing nomenclature for non-current-version) when versioning is present. this should solve all problems related to libraries with symbol versioning as long as all binaries involved are up-to-date (compatible with the latest-version symbols), and it's the needed behavior for dlsym under all circumstances.
* add system for resetting TLS to initial valuesRich Felker2013-08-031-0/+13
| | | | | | | | | | | | | | | this is needed for reused threads in the SIGEV_THREAD timer notification system, and could be reused elsewhere in the future if needed, though it should be refactored for such use. for static linking, __init_tls.c is simply modified to export the TLS info in a structure with external linkage, rather than using statics. this perhaps makes the code more clear, since the statics were poorly named for statics. the new __reset_tls.c is only linked if it is used. for dynamic linking, the code is in dynlink.c. sharing code with __copy_tls is not practical since __reset_tls must also re-zero thread-local bss.
* move RPATH search after LD_LIBRARY_PATH searchRich Felker2013-08-021-2/+2
| | | | | | | | | this is the modern way, and the only way that makes any sense. glibc has this complicated mechanism with RPATH and RUNPATH that controls whether RPATH is processed before or after LD_LIBRARY_PATH, presumably to support legacy binaries, but there is no compelling reason to support this, and better behavior is obtained by just fixing the search order.
* if map_library has allocated a buffer for phdrs, free it on success tooRich Felker2013-08-021-0/+1
| | | | this fixes an oversight in the previous commit.
* improve error handling in map_library and support long phdrsRich Felker2013-08-021-12/+21
| | | | | | | previously, errno could be meaningless when the caller wrote it to the dlerror string or stderr. try to make it meaningful. also, fix incorrect check for over-long program headers and instead actually support them by allocating memory if needed.
* fix uninitialized dyn variable in map_libraryRich Felker2013-08-021-1/+1
| | | | | this can only happen for invalid library files, but they were not detected reliably because the variable was uninitialized.
* fix theoretical out-of-bound access in dynamic linkerRich Felker2013-07-311-1/+1
| | | | | | | | one of the arguments to memcmp may be shorter than the length l-3, and memcmp is under no obligation not to access past the first byte that differs. instead use strncmp which conveys the correct semantics. the performance difference is negligible here and since the code is only use for shared libc, both functions are already linked anyway.
* prevent passing PT_INTERP name to dlopen from double-loading libcRich Felker2013-07-311-6/+11
| | | | | | | | | | | | | the dev/inode for the main app and the dynamic linker ("interpreter") are not available, so the subsequent checks don't work. in general we don't want to make exact string matches to existing libraries prevent loading new ones, since this breaks loading upgraded modules in module-loading systems. so instead, special-case it. the motivation for this fix is that calling dlopen on the names returned by dl_iterate_phdr or walking the link map (obtained by dlinfo) seem to be the only methods available to an application to actually get a list of open dso handles.
* add some sanity checks in dynamic loader codeRich Felker2013-07-311-0/+10
| | | | | | | | reject elf files which are not ET_EXEC/ET_DYN type as bad exec format, and reject ET_EXEC files when they cannot be loaded at the correct address, since they are not relocatable at runtime. the main practical benefit of this is to make dlopen of the main program fail rather than producing an unsafe-to-use handle.
* fix bug where read error was treated as success reading library headersRich Felker2013-07-311-1/+1
|
* don't call null pointer if DT_INIT/DT_FINI are nullRich Felker2013-07-311-2/+2
| | | | | | | | it's not clear to me why the linker even outputs these headers if they are null, but apparently it does so. with the default startfiles, they will never be null anyway, but this patch allows eliminating crti, crtn, crtbegin, and crtend (leaving only crt1) if the toolchain is using init_array/fini_array (or for a C-only, no-ctor environment).
* fix indention-with-spacesRich Felker2013-07-271-1/+1
|
* make ldd report the libc/dynamic linker itselfRich Felker2013-07-261-0/+22
|
* fix computation of entry point and main app phdrs when invoking via ldsoRich Felker2013-07-261-3/+1
| | | | | | | | | | | entry point was wrong for PIE. e_entry was being treated as an absolute value, whereas it's actually relative to the load address (which is zero for non-PIE). phdr pointer was wrong for non-PIE. e_phoff was being treated as load-address-relative, whereas it's actually a file offset in the ELF file. in any case, map_library was already computing it correctly, and the incorrect code in __dynlink was overwriting it with junk.
* support STB_GNU_UNIQUE symbol bindings in dynamic linkerRich Felker2013-07-241-1/+1
| | | | | | | | | these are needed for some C++ library binaries including most builds of libstdc++. I'm not entirely clear on the rationale. this patch does not implement any special semantics for them, but as far as I can tell, no special treatment is needed in correctly-linked programs; this binding seems to exist only for catching incorrectly-linked programs.
* move the dynamic linker's jmp_buf from static to automatic storageRich Felker2013-07-241-5/+7
| | | | | this more than compensates for the size increase of jmp_buf, and greatly reduces bss/data size on archs with huge jmp_buf.
* disable legacy init/fini processing on ARMRich Felker2013-07-221-0/+4
| | | | | | | | | | | since the old, poorly-thought-out musl approach to init/fini arrays on ARM (when it was the only arch that needed them) was to put the code in crti/crtn and have the legacy _init/_fini code run the arrays, adding proper init/fini array support caused the arrays to get processed twice on ARM. I'm not sure skipping legacy init/fini processing is the best solution to the problem, but it works, and it shouldn't break anything since the legacy init/fini system was never used for ARM EABI.
* add support for init/fini array in main program, and greatly simplifyRich Felker2013-07-211-8/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | modern (4.7.x and later) gcc uses init/fini arrays, rather than the legacy _init/_fini function pasting and crtbegin/crtend ctors/dtors system, on most or all archs. some archs had already switched a long time ago. without following this change, global ctors/dtors will cease to work under musl when building with new gcc versions. the most surprising part of this patch is that it actually reduces the size of the init code, for both static and shared libc. this is achieved by (1) unifying the handling main program and shared libraries in the dynamic linker, and (2) eliminating the glibc-inspired rube goldberg machine for passing around init and fini function pointers. to clarify, some background: the function signature for __libc_start_main was based on glibc, as part of the original goal of being able to run some glibc-linked binaries. it worked by having the crt1 code, which is linked into every application, static or dynamic, obtain and pass pointers to the init and fini functions, which __libc_start_main is then responsible for using and recording for later use, as necessary. however, in neither the static-linked nor dynamic-linked case do we actually need crt1.o's help. with dynamic linking, all the pointers are available in the _DYNAMIC block. with static linking, it's safe to simply access the _init/_fini and __init_array_start, etc. symbols directly. obviously changing the __libc_start_main function signature in an incompatible way would break both old musl-linked programs and glibc-linked programs, so let's not do that. instead, the function can just ignore the information it doesn't need. new archs need not even provide the useless args in their versions of crt1.o. existing archs should continue to provide it as long as there is an interest in having newly-linked applications be able to run on old versions of musl; at some point in the future, this support can be removed.
* fix order of fini_array execution for shared libsRich Felker2013-07-211-2/+2
|
* add support for init_array/fini_array ctors/dtors to dynamic linkerRich Felker2013-07-201-2/+13
|
* make the dynamic linker find its path file relative to its own locationRich Felker2013-07-181-1/+20
| | | | | | | | | | | | | | | | | | | prior to this change, using a non-default syslibdir was impractical on systems where the ordinary library paths contain musl-incompatible library files. the file containing search paths was always taken from /etc, which would either correspond to a system-wide musl installation, or fail to exist at all, resulting in searching of the default library path. the new search strategy is safe even for suid programs because the pathname used comes from the PT_INTERP header of the program being run, rather than any external input. as part of this change, I have also begun differentiating the names of arch variants that differ by endianness or floating point calling convention. the corresponding changes in the build system and and gcc wrapper script (to use an alternate dynamic linker name) for these configurations have not yet been made.
* fix invalid library phdr pointers passed to callback from dl_iterate_phdrRich Felker2013-07-101-9/+16
| | | | | | | | | | | | map_library was saving pointers to an automatic-storage buffer rather than pointers into the mapping. this should be a fairly simple fix, but the patch here is slightly complicated by two issues: 1. supporting gratuitously obfuscated ELF files where the program headers are not right at the beginning of the file. 2. cleaning up the map_library function so that data isn't clobbered by the time we need it.
* implement minimal dlinfo functionRich Felker2013-06-291-0/+12
|
* fix missing synchronization in calls from dynamic linker to global ctorsRich Felker2013-06-291-0/+4
| | | | | | | | | | | | | this change is needed to correctly handle the case where a constructor creates a new thread which calls dlopen. previously, the lock was not held in this case. the reason for the complex logic to avoid locking whenever possible is that, since the mutex is recursive, it will need to inspect the thread pointer to get the current thread's tid, and this requires initializing the thread pointer. we do not want non-multi-threaded programs to attempt to access the thread pointer unnecessarily; doing so could make them crash on ancient kernels that don't support threads but which may otherwise be capable of running the program.
* remove useless conditional before free from dynamic linker path codeRich Felker2013-06-261-1/+1
|
* fix dynamic linker handling of empty path file or error reading path fileRich Felker2013-06-261-4/+3
| | | | | | | | | | | | | previously, the path string was being used despite being invalid. with this change, empty path file or error reading the path file is treated as an empty path. this is preferable to falling back to a default path, so that attacks to prevent reading of the path file could not result in loading incorrect and possibly dangerous (outdated or mismatching ABI) libraries from. the code to strip the final newline has also been removed; now that newline is accepted as a delimiter, it's harmless to leave it in place.
* make newline-delimited dynamic linker path file actually workRich Felker2013-06-251-1/+1
| | | | | | | apparently the original commit was never tested properly, since getline was only ever reading one line. the intent was to read the entire file, so use getdelim with the null byte as delimiter as a cheap way to read a whole file into memory.
* ensure that thread dtv pointer is never null to optimize __tls_get_addrRich Felker2013-06-031-4/+4
|
* make dynamic linker accept : or \n as path separatorRich Felker2013-04-201-8/+8
| | | | | | | | | | | | | this allows /etc/ld-musl-$(ARCH).path to contain one path per line, which is much more convenient for users than the :-delimited format, which was a source of repeated and unnecessary confusion. for simplicity, \n is also accepted in environment variables, though it should probably not be used there. at the same time, issues with overly long paths invoking UB or getting truncated have been fixed. such issues should not have arisen with the environment (which is size-limited) but could have been generated by a path file larger than 2**31 bytes in length.
* fix uninitialized map_len being used in munmap failure paths in load_libraryRich Felker2013-02-021-3/+2
| | | | | | this bug seems to have been introduced when the map_library signatures was changed to return the mapping in a temp dso structure instead of into separate variables.
* add support for RTLD_NOLOAD to dlopenRich Felker2013-01-231-3/+7
| | | | | | | | based on patch by Pierre Carrier <pierre@gcarrier.fr> that just added the flag constant, but with minimal additional code so that it actually works as documented. this is a nonstandard option but some major software (reportedly, Firefox) uses it and it was easy to add anyway.
* fix regression in dlsym: rejection of special RTLD_* handles as invalidRich Felker2013-01-231-1/+2
|