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.

Reply via email to