From: Waldemar Kozaczuk <[email protected]> Committer: WALDEMAR KOZACZUK <[email protected]> Branch: master
Support executing dynamically-linked executables via Linux dynamic linker This PR enhances OSv to be able to launch dynamically linked executables(PIEs or non-PIEs) using the Linux dynamic linker - ld-linux-x86-64.so.2 on x86_64 or ld-linux-aarch64.so.1 on aarch64 like so: ./scripts/run.py -e '/lib64/ld-linux-x86-64.so.2 /hello' The motivation is to allow running dynamically linked executables that depend on libc symbols not implemented by the OSv kernel. In this case, the executables launched this way would interact only through system calls just like the statically linked ones do. Actually, my experiments so far seem to show that there are no extra changes needed beyond the same code enhancements to support statically linked executables. When executing dynamically linked executable, Linux reads the PT_INTERP segment to determine the program interpreter to launch with (typically ld-linux-x86-64.so.2), probably unmaps the executable, loads the program interpreter and delegates futher execution by jumping to its entry point. On OSv we could implement similar logic but even though not complicated it would involve some not in significant coding. So this patch takes a simpler approach where we assume a user would explicitly run the Linux program interpreter and pass the path of the executable as its parameter which by the way is a valid thing to do on Linux. To that end we enhance OSv dynamic linker to process ld-linux-x86-64.so.2 in the same way we process a statically linked executable (in reality ld-linux-x86-64.so.2 is a statically linked shared library with non-zero entry point): - do not relocate - do not call INIT and FINI functions - launch by jumping to the entry point We detect if given ELF is a Linux program interpreter by comparing its soname to the architecture specific string - ld-linux-x86-64.so.2 on x86_64 and ld-linux-aarch64.so.1 on aarch64. Fixes #1266 Signed-off-by: Waldemar Kozaczuk <[email protected]> --- diff --git a/core/app.cc b/core/app.cc --- a/core/app.cc +++ b/core/app.cc @@ -217,7 +217,7 @@ application::application(const std::string& command, throw launch_error("Failed to load object: " + command); } - if (_lib->is_statically_linked_executable()) { + if (_lib->is_statically_linked_executable() || _lib->is_linux_dl()) { //Augment auxiliary vector with extra entries like AT_PHDR, AT_ENTRY, etc //that are necessary by a static executable to bootstrap itself augment_auxv(); @@ -326,7 +326,7 @@ void application::main() elf::get_program()->init_library(_args.size(), _argv.get()); sched::thread::current()->set_name(_command); - if (_lib->is_statically_linked_executable()) { + if (_lib->is_statically_linked_executable() || _lib->is_linux_dl()) { run_entry_point(_lib->entry_point(), _args.size(), _argv.get(), _argv_size); } else { if (_main) { diff --git a/core/elf.cc b/core/elf.cc --- a/core/elf.cc +++ b/core/elf.cc @@ -1169,7 +1169,7 @@ std::string object::pathname() // Run the object's static constructors or similar initialization void object::run_init_funcs(int argc, char** argv) { - if (is_statically_linked_executable()) { + if (is_statically_linked_executable() || is_linux_dl()) { return; } // Invoke any init functions if present and pass in argc and argv @@ -1197,7 +1197,7 @@ void object::run_init_funcs(int argc, char** argv) // Run the object's static destructors or similar finalization void object::run_fini_funcs() { - if (is_statically_linked_executable()) { + if (is_statically_linked_executable() || is_linux_dl()) { return; } if(!_init_called){ @@ -1323,11 +1323,11 @@ program::program(void* addr) // Our kernel already supplies the features of a bunch of traditional // shared libraries: static const auto supplied_modules = { + linux_dl_soname, "libresolv.so.2", "libc.so.6", "libm.so.6", #ifdef __x86_64__ - "ld-linux-x86-64.so.2", "libc.musl-x86_64.so.1", // As noted in issue #1040 Boost version 1.69.0 and above is // compiled with hidden visibility, so even if the kernel uses @@ -1340,7 +1340,6 @@ program::program(void* addr) #endif #endif /* __x86_64__ */ #ifdef __aarch64__ - "ld-linux-aarch64.so.1", #if BOOST_VERSION < 106900 #if HIDE_SYMBOLS < 1 "libboost_system-mt.so.1.55.0", @@ -1478,7 +1477,7 @@ program::load_object(std::string name, std::vector<std::string> extra_path, //Do not relocate static executables as they are linked with its own //dynamic linker. Also do not try to load any dependant libraries //as they do not apply to statically linked executables. - if (!ef->is_statically_linked_executable()) { + if (!ef->is_statically_linked_executable() && !ef->is_linux_dl()) { ef->load_needed(loaded_objects); ef->relocate(); ef->fix_permissions(); diff --git a/include/osv/elf.hh b/include/osv/elf.hh --- a/include/osv/elf.hh +++ b/include/osv/elf.hh @@ -303,6 +303,13 @@ struct Elf64_Sym { Elf64_Xword st_size; /* Size of object (e.g., common) */ }; +#ifdef __x86_64__ + constexpr const char *linux_dl_soname = "ld-linux-x86-64.so.2"; +#endif +#ifdef __aarch64__ + constexpr const char *linux_dl_soname = "ld-linux-aarch64.so.1"; +#endif + class program; struct symbol_module; @@ -405,6 +412,7 @@ public: // Absence of PT_INTERP is not enough to determine it is a statically linked executable // as shared libraries also as missing PT_INTERP. bool is_statically_linked_executable() { return !_is_dynamically_linked_executable && !is_shared_library(); } + bool is_linux_dl() { return this->soname() == linux_dl_soname; } ulong get_tls_size(); ulong get_aligned_tls_size(); void copy_local_tls(void* to_addr); -- You received this message because you are subscribed to the Google Groups "OSv Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/000000000000aed3e9060954e647%40google.com.
