The issue #1045 exposed a bug in the dynamic linker when processing
some headers like PT_NOTE require accessing data in the PT_LOAD segments.
If PT_NOTE headers come earlier than PT_NOTE we end up with the page fault
as the portions of ELF file have not been mapped yet.
This patch separates loading of segments - load_segments() - from
processing headers by adding new method - process_headers().
Fixes #1045
Signed-off-by: Waldemar Kozaczuk <
jwkoz...@gmail.com>
---
core/elf.cc | 17 ++++++++++++++---
include/osv/elf.hh | 1 +
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/core/elf.cc b/core/elf.cc
index 39de219f..73834b19 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -452,14 +452,22 @@ extern "C" char _pie_static_tls_start, _pie_static_tls_end;
void object::load_segments()
{
elf_debug("Loading segments\n");
+ for (unsigned i = 0; i < _ehdr.e_phnum; ++i) {
+ auto &phdr = _phdrs[i];
+ if (phdr.p_type == PT_LOAD) {
+ load_segment(phdr);
+ }
+ }
+}
+
+void object::process_headers()
+{
+ elf_debug("Processing headers\n");
for (unsigned i = 0; i < _ehdr.e_phnum; ++i) {
auto &phdr = _phdrs[i];
switch (phdr.p_type) {
case PT_NULL:
break;
- case PT_LOAD:
- load_segment(phdr);
- break;
case PT_DYNAMIC:
_dynamic_table = reinterpret_cast<Elf64_Dyn*>(_base + phdr.p_vaddr);
break;
@@ -495,6 +503,7 @@ void object::load_segments()
}
break;
}
+ case PT_LOAD:
case PT_PHDR:
case PT_GNU_STACK:
case PT_GNU_RELRO:
@@ -1233,6 +1242,7 @@ program::program(void* addr)
_core->set_base(program_base);
assert(_core->module_index() == core_module_index);
_core->load_segments();
+ _core->process_headers();
set_search_path({"/", "/usr/lib"});
// Our kernel already supplies the features of a bunch of traditional
// shared libraries:
@@ -1361,6 +1371,7 @@ program::load_object(std::string name, std::vector<std::string> extra_path,
_modules_rcu.assign(new_modules.release());
osv::rcu_dispose(old_modules);
ef->load_segments();
+ ef->process_headers();
if (!ef->is_non_pie_executable())
_next_alloc = ef->end();
add_debugger_obj(ef.get());
diff --git a/include/osv/elf.hh b/include/osv/elf.hh
index 3722da9e..1dac6c08 100644
--- a/include/osv/elf.hh
+++ b/include/osv/elf.hh
@@ -348,6 +348,7 @@ public:
void* end() const;
Elf64_Sym* lookup_symbol(const char* name, bool self_lookup);
void load_segments();
+ void process_headers();
void unload_segments();
void fix_permissions();
void* resolve_pltgot(unsigned index);
--
2.20.1