From: Waldemar Kozaczuk <[email protected]> Committer: Waldemar Kozaczuk <[email protected]> Branch: master
dynamic linker: support loading and processing static ELF This patch enhances dynamic linker to support loading and processing statically linked executables. This does not mean OSv will now be able to run such ELFs: there are still many key elements missing which will added in subsequent patches. This patch however modifies dynamic linker to properly detect statically linked PIEs and non-PIEs and skip/adjust relevant parts of the processing logic where necessary: - adjusts object::set_base() to set _base to 0 for any position dependent ELF (non PIC) both statically or dynamically linked - modifies object::fix_permissions() to skip RELRO processing for statically linked executables as it does not apply (at least for now) - adjusts the lookup_symbol_*() and lookup_addr() methods to abort if DT_SYMTAB and DT_STRTAB not present accordingly - adjusts load_needed() to abort loading dependent objects if DT_NEEDED not present Signed-off-by: Waldemar Kozaczuk <[email protected]> --- diff --git a/core/elf.cc b/core/elf.cc --- a/core/elf.cc +++ b/core/elf.cc @@ -249,9 +249,6 @@ const char * object::symbol_name(const Elf64_Sym * sym) { } void* object::entry_point() const { - if (!_is_dynamically_linked_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 { @@ -536,8 +533,8 @@ 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_dynamically_linked_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_dynamically_linked_executable && _tls_segment) { auto app_tls_size = get_aligned_tls_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; @@ -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,7 +378,7 @@ 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_dynamically_linked_executable() { return _is_dynamically_linked_executable; } ulong get_tls_size(); @@ -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; -- 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/00000000000023f8770604327a61%40google.com.
