From: Nadav Har'El <n...@scylladb.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

Merge 'Dynamic linker: support loading and processing statically linked 
executables' from WALDEMAR KOZACZUK

The two commits provide necessary modifications to the OSv dynamic linker to 
support loading and processing statically linked executables.

Please note these changes are NOT enough to make OSv run statically linked 
executables.

Closes #1253

* github.com:cloudius-systems/osv:
  dynamic linker: support loading and processing static ELF
  dynamic linker: rename is_executable to is_dynamically_linked_executable

---
diff --git a/arch/aarch64/arch-elf.cc b/arch/aarch64/arch-elf.cc
--- a/arch/aarch64/arch-elf.cc
+++ b/arch/aarch64/arch-elf.cc
@@ -66,7 +66,7 @@ bool object::arch_relocate_rela(u32 type, u32 sym, void *addr,
         if (sym) {
             auto sm = symbol(sym);
             ulong tls_offset;
-            if (sm.obj->is_executable()) {
+            if (sm.obj->is_dynamically_linked_executable()) {
                 // If this is an executable (pie or position-dependant one)
                 // then the variable is located in the reserved slot of the TLS
                 // right where the kernel TLS lives
@@ -119,7 +119,7 @@ void object::arch_relocate_tls_desc(u32 sym, void *addr, 
Elf64_Sxword addend)
     ulong tls_offset;
     if (sym) {
         auto sm = symbol(sym);
-        if (sm.obj->is_executable() || sm.obj->is_core()) {
+        if (sm.obj->is_dynamically_linked_executable() || sm.obj->is_core()) {
             // If this is an executable (pie or position-dependant one)
             // then the variable is located in the reserved slot of the TLS
             // right where the kernel TLS lives
@@ -163,7 +163,7 @@ void object::prepare_initial_tls(void* buffer, size_t size,
 
 void object::prepare_local_tls(std::vector<ptrdiff_t>& offsets)
 {
-    if (!_static_tls && !is_executable()) {
+    if (!_static_tls && !is_dynamically_linked_executable()) {
         return;
     }
 
diff --git a/arch/aarch64/arch-switch.hh b/arch/aarch64/arch-switch.hh
--- a/arch/aarch64/arch-switch.hh
+++ b/arch/aarch64/arch-switch.hh
@@ -120,7 +120,7 @@ void thread::setup_tcb()
         assert(obj);
         user_tls_size = obj->initial_tls_size();
         user_tls_data = obj->initial_tls();
-        if (obj->is_executable()) {
+        if (obj->is_dynamically_linked_executable()) {
            executable_tls_size = obj->get_tls_size();
         }
     }
diff --git a/arch/x64/arch-elf.cc b/arch/x64/arch-elf.cc
--- a/arch/x64/arch-elf.cc
+++ b/arch/x64/arch-elf.cc
@@ -138,7 +138,7 @@ bool object::arch_relocate_rela(u32 type, u32 sym, void 
*addr,
         if (sym) {
             auto sm = symbol(sym);
             ulong tls_offset;
-            if (sm.obj->is_executable()) {
+            if (sm.obj->is_dynamically_linked_executable()) {
                 // If this is an executable (pie or position-dependant one)
                 // then the variable is located in the reserved slot of the TLS
                 // right where the kernel TLS lives
@@ -202,7 +202,7 @@ void object::prepare_initial_tls(void* buffer, size_t size,
 
 void object::prepare_local_tls(std::vector<ptrdiff_t>& offsets)
 {
-    if (!_static_tls && !is_executable()) {
+    if (!_static_tls && !is_dynamically_linked_executable()) {
         return;
     }
 
diff --git a/arch/x64/arch-switch.hh b/arch/x64/arch-switch.hh
--- a/arch/x64/arch-switch.hh
+++ b/arch/x64/arch-switch.hh
@@ -210,7 +210,7 @@ void thread::setup_tcb()
         assert(obj);
         user_tls_size = obj->initial_tls_size();
         user_tls_data = obj->initial_tls();
-        if (obj->is_executable()) {
+        if (obj->is_dynamically_linked_executable()) {
            executable_tls_size = obj->get_tls_size();
            aligned_executable_tls_size = obj->get_aligned_tls_size();
         }
diff --git a/core/elf.cc b/core/elf.cc
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -123,7 +123,7 @@ object::object(program& prog, std::string pathname)
     , _initial_tls_size(0)
     , _dynamic_table(nullptr)
     , _module_index(_prog.register_dtv(this))
-    , _is_executable(false)
+    , _is_dynamically_linked_executable(false)
     , _init_called(false)
     , _eh_frame(0)
     , _visibility_thread(nullptr)
@@ -249,9 +249,6 @@ const char * object::symbol_name(const Elf64_Sym * sym) {
 }
 
 void* object::entry_point() const {
-    if (!_is_executable) {
-        return nullptr;
-    }
     return _base + _ehdr.e_entry;
 }
 
@@ -366,13 +363,13 @@ void object::set_base(void* base)
                               [](const Elf64_Phdr* a, const Elf64_Phdr* b)
                                   { return a->p_vaddr < b->p_vaddr; });
 
-    if (!is_core() && is_non_pie_executable()) {
-        // Verify non-PIE executable does not collide with the kernel
+    if (!is_core() && !is_pic()) {
+        // Verify non-PIC executable ((aka position dependent)) does not 
collide with the kernel
         if (intersects_with_kernel(p->p_vaddr) || 
intersects_with_kernel(q->p_vaddr + q->p_memsz)) {
-            abort("Non-PIE executable [%s] collides with kernel: [%p-%p] !\n",
+            abort("Non-PIC executable [%s] collides with kernel: [%p-%p] !\n",
                     pathname().c_str(), p->p_vaddr, q->p_vaddr + q->p_memsz);
         }
-        // Override the passed in value as the base for non-PIEs (Position 
Dependant Executables)
+        // Override the passed in value as the base for non-PICs (Position 
Dependant Executables)
         // needs to be set to 0 because all the addresses in it are absolute
         _base = 0x0;
     } else {
@@ -484,7 +481,7 @@ void object::process_headers()
             _dynamic_table = reinterpret_cast<Elf64_Dyn*>(_base + 
phdr.p_vaddr);
             break;
         case PT_INTERP:
-            _is_executable = true;
+            _is_dynamically_linked_executable = true;
             break;
         case PT_NOTE: {
             if (phdr.p_memsz < 16) {
@@ -536,10 +533,10 @@ void object::process_headers()
             abort("Unknown p_type in executable %s: %d\n", pathname(), 
phdr.p_type);
         }
     }
-    if (!is_core() && _ehdr.e_type == ET_EXEC && !_is_executable) {
-        abort("Statically linked executables are not supported!\n");
+    if (!is_core() && is_statically_linked()) {
+        abort("Statically linked executables are not supported yet!\n");
     }
-    if (_is_executable && _tls_segment) {
+    if (_is_dynamically_linked_executable && _tls_segment) {
         auto app_tls_size = get_aligned_tls_size();
         ulong pie_static_tls_maximum_size = &_pie_static_tls_end - 
&_pie_static_tls_start;
         if (app_tls_size > pie_static_tls_maximum_size) {
@@ -600,6 +597,12 @@ void object::fix_permissions()
         make_text_writable(false);
     }
 
+    //Full RELRO applies to dynamically linked executables only
+    if (is_statically_linked()) {
+        return;
+    }
+
+    //Process GNU_RELRO segments only to make GOT and others read-only
     for (auto&& phdr : _phdrs) {
         if (phdr.p_type != PT_GNU_RELRO)
             continue;
@@ -888,6 +891,9 @@ constexpr Elf64_Versym old_version_symbol_mask = 
Elf64_Versym(1) << 15;
 
 Elf64_Sym* object::lookup_symbol_old(const char* name)
 {
+    if (!dynamic_exists(DT_SYMTAB)) {
+        return nullptr;
+    }
     auto symtab = dynamic_ptr<Elf64_Sym>(DT_SYMTAB);
     auto strtab = dynamic_ptr<char>(DT_STRTAB);
     auto hashtab = dynamic_ptr<Elf64_Word>(DT_HASH);
@@ -917,6 +923,9 @@ dl_new_hash(const char *s)
 
 Elf64_Sym* object::lookup_symbol_gnu(const char* name, bool self_lookup)
 {
+    if (!dynamic_exists(DT_SYMTAB)) {
+        return nullptr;
+    }
     auto symtab = dynamic_ptr<Elf64_Sym>(DT_SYMTAB);
     auto strtab = dynamic_ptr<char>(DT_STRTAB);
     auto hashtab = dynamic_ptr<Elf64_Word>(DT_GNU_HASH);
@@ -1019,6 +1028,9 @@ dladdr_info object::lookup_addr(const void* addr)
     if (addr < _base || addr >= _end) {
         return ret;
     }
+    if (!dynamic_exists(DT_STRTAB)) {
+        return ret;
+    }
     ret.fname = _pathname.c_str();
     ret.base = _base;
     auto strtab = dynamic_ptr<char>(DT_STRTAB);
@@ -1068,6 +1080,9 @@ static std::string dirname(std::string path)
 
 void object::load_needed(std::vector<std::shared_ptr<object>>& loaded_objects)
 {
+    if (!dynamic_exists(DT_NEEDED)) {
+        return;
+    }
     std::vector<std::string> rpath;
 
     std::string rpath_str;
@@ -1263,7 +1278,7 @@ void object::init_static_tls()
         if (obj->is_core()) {
             continue;
         }
-        if (obj->is_executable()) {
+        if (obj->is_dynamically_linked_executable()) {
             obj->prepare_local_tls(_initial_tls_offsets);
             elf_debug("Initialized local-exec static TLS for %s\n", 
obj->pathname().c_str());
         }
@@ -1462,7 +1477,7 @@ program::load_object(std::string name, 
std::vector<std::string> extra_path,
         osv::rcu_dispose(old_modules);
         ef->load_segments();
         ef->process_headers();
-        if (!ef->is_non_pie_executable())
+        if (ef->is_pic())
            _next_alloc = ef->end();
         add_debugger_obj(ef.get());
         loaded_objects.push_back(ef);
diff --git a/include/osv/elf.hh b/include/osv/elf.hh
--- a/include/osv/elf.hh
+++ b/include/osv/elf.hh
@@ -378,9 +378,9 @@ public:
     size_t initial_tls_size() { return _initial_tls_size; }
     void* initial_tls() { return _initial_tls.get(); }
     void* get_tls_segment() { return _tls_segment; }
-    bool is_non_pie_executable() { return _ehdr.e_type == ET_EXEC; }
+    bool is_pic() { return _ehdr.e_type != ET_EXEC; }
     std::vector<ptrdiff_t>& initial_tls_offsets() { return 
_initial_tls_offsets; }
-    bool is_executable() { return _is_executable; }
+    bool is_dynamically_linked_executable() { return 
_is_dynamically_linked_executable; }
     ulong get_tls_size();
     ulong get_aligned_tls_size();
     void copy_local_tls(void* to_addr);
@@ -415,6 +415,7 @@ private:
     void prepare_local_tls(std::vector<ptrdiff_t>& offsets);
     void alloc_static_tls();
     void make_text_writable(bool flag);
+    bool is_statically_linked() { return !_is_dynamically_linked_executable && 
_ehdr.e_entry; }
 protected:
     program& _prog;
     std::string _pathname;
@@ -435,7 +436,7 @@ protected:
     Elf64_Dyn* _dynamic_table;
     ulong _module_index;
     std::unique_ptr<char[]> _section_names_cache;
-    bool _is_executable;
+    bool _is_dynamically_linked_executable;
     bool is_core();
     bool _init_called;
     void* _eh_frame;
@@ -462,7 +463,7 @@ protected:
     bool arch_relocate_jump_slot(symbol_module& sym, void *addr, Elf64_Sxword 
addend);
     void arch_relocate_tls_desc(u32 sym, void *addr, Elf64_Sxword addend);
     size_t static_tls_end() {
-        if (is_core() || is_executable()) {
+        if (is_core() || _is_dynamically_linked_executable) {
             return 0;
         }
         return _static_tls_offset + get_tls_size();

-- 
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 osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/0000000000003b0c070604327afc%40google.com.

Reply via email to