This patch provides necessary changes to OSv dynamic linker
to allow running non-PIEs (= Position Dependant Executables)
as long as they do not collide with kernel.

Please note this patch does not fully address issue #190
though it provides necessary groundwork to fully address it in future.
To truly support running unmodified arbitrary non-PIEs
(that typically load at 0x400000 = 4th MB) we need
to modify OSv to load kernel way higher that 0x200000.

There are 2 ways to run non-PIEs with OSv with this patch:

1) Link it by forcing text segment address so it does
   not collide with kernel using -Wl,-Ttext-segment,0x?????? option.

2) Change kernel_base in OSv makefile to a higher address that
   makes it not collide with the executable (for example 0xa00000);
   most non-PIEs by default load at 0x400000

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
---
 core/elf.cc            | 35 ++++++++++++++++++++++++-----------
 include/osv/elf.hh     |  1 +
 modules/tests/Makefile |  9 +++++++--
 tests/tst-non-pie.cc   |  6 ++++++
 4 files changed, 38 insertions(+), 13 deletions(-)
 create mode 100644 tests/tst-non-pie.cc

diff --git a/core/elf.cc b/core/elf.cc
index fc2ee0c3..42525043 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -34,6 +34,9 @@ TRACEPOINT(trace_elf_unload, "%s", const char *);
 TRACEPOINT(trace_elf_lookup, "%s", const char *);
 TRACEPOINT(trace_elf_lookup_addr, "%p", const void *);
 
+extern void* elf_start;
+extern size_t elf_size;
+
 using namespace boost::range;
 
 namespace {
@@ -267,15 +270,6 @@ void file::load_elf_header()
           || _ehdr.e_ident[EI_OSABI] == 0)) {
         throw osv::invalid_elf_error("bad os abi");
     }
-    // We currently only support running ET_DYN objects (shared library or
-    // position-independent executable). In the future we can add support for
-    // ET_EXEC (ordinary, position-dependent executables) but it will require
-    // loading them at their specified address and moving the kernel out of
-    // their way.
-    if (_ehdr.e_type != ET_DYN) {
-        throw osv::invalid_elf_error(
-                "bad executable type (only shared-object or PIE supported)");
-    }
 }
 
 void file::read(Elf64_Off offset, void* data, size_t size)
@@ -297,17 +291,35 @@ void* align(void* addr, ulong align, ulong offset)
 
 }
 
+static bool intersects_with_kernel(Elf64_Addr elf_addr)
+{
+    void *addr = reinterpret_cast<void*>(elf_addr);
+    return addr >= elf_start && addr < elf_start + elf_size;
+}
+
 void object::set_base(void* base)
 {
     auto p = std::min_element(_phdrs.begin(), _phdrs.end(),
                               [](Elf64_Phdr a, Elf64_Phdr b)
                                   { return a.p_type == PT_LOAD
                                         && a.p_vaddr < b.p_vaddr; });
-    _base = align(base, p->p_align, p->p_vaddr & (p->p_align - 1)) - 
p->p_vaddr;
     auto q = std::min_element(_phdrs.begin(), _phdrs.end(),
                               [](Elf64_Phdr a, Elf64_Phdr b)
                                   { return a.p_type == PT_LOAD
                                         && a.p_vaddr > b.p_vaddr; });
+
+    if (is_non_pie_executable() && base != ((void*)ELF_IMAGE_START)) {
+        // Verify non-PIE executable 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",
+                    pathname().c_str(), p->p_vaddr, q->p_vaddr + q->p_memsz);
+        }
+        // The base for non-PIEs ( = Position Dependant Executables) should be 
set to 0
+        _base = 0x0;
+    } else {
+        _base = align(base, p->p_align, p->p_vaddr & (p->p_align - 1)) - 
p->p_vaddr;
+    }
+
     _end = _base + q->p_vaddr + q->p_memsz;
 }
 
@@ -1223,7 +1235,8 @@ 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();
-        _next_alloc = ef->end();
+        if (!ef->is_non_pie_executable())
+           _next_alloc = ef->end();
         add_debugger_obj(ef.get());
         loaded_objects.push_back(ef);
         ef->load_needed(loaded_objects);
diff --git a/include/osv/elf.hh b/include/osv/elf.hh
index 894ea237..775d8c8d 100644
--- a/include/osv/elf.hh
+++ b/include/osv/elf.hh
@@ -365,6 +365,7 @@ public:
     void init_static_tls();
     size_t initial_tls_size() { return _initial_tls_size; }
     void* initial_tls() { return _initial_tls.get(); }
+    bool is_non_pie_executable() { return _ehdr.e_type == ET_EXEC; }
     std::vector<ptrdiff_t>& initial_tls_offsets() { return 
_initial_tls_offsets; }
 protected:
     virtual void load_segment(const Elf64_Phdr& segment) = 0;
diff --git a/modules/tests/Makefile b/modules/tests/Makefile
index b0bfb031..1489c536 100644
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -67,7 +67,12 @@ $(out)/tests/tst-getopt-pie.o: $(src)/tests/tst-getopt.cc
        $(makedir)
        $(call quiet, $(CXX) $(CXXFLAGS) -c -o $@ $<, CXX $*.cc)
 $(out)/tests/tst-getopt-pie.so: $(out)/tests/tst-getopt-pie.o
-       $(call quiet, $(CXX) $(CXXFLAGS) -pie -o $@ $< $(LIBS), LD $*.so)
+       $(call quiet, $(CXX) $(CXXFLAGS) -pie -o $@ $< $(LIBS), LD $@)
+
+comma := ,
+$(out)/tests/tst-non-pie.so: CXXFLAGS:=$(subst -fPIC,-no-pie 
-Wl$(comma)-Ttext-segment$(comma)0xf000000,$(CXXFLAGS))
+$(out)/tests/tst-non-pie.so: $(src)/tests/tst-non-pie.cc
+       $(call quiet, $(CXX) $(CXXFLAGS) -o $@ $< $(LIBS), LD $@)
 
 # The rofs test image mounts /tmp as ramfs and 4 tests that exercise file 
system
 # fail due to some unresolved bugs or other shortcomings of the ramfs 
implementation
@@ -124,7 +129,7 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so 
tst-bsd-evh.so \
        tst-ttyname.so tst-pthread-barrier.so tst-feexcept.so tst-math.so \
        tst-sigaltstack.so tst-fread.so tst-tcp-cork.so tst-tcp-v6.so \
        tst-calloc.so tst-crypt.so tst-non-fpic.so tst-small-malloc.so \
-       tst-mmx-fpu.so tst-getopt.so tst-getopt-pie.so
+       tst-mmx-fpu.so tst-getopt.so tst-getopt-pie.so tst-non-pie.so
 #      libstatic-thread-variable.so tst-static-thread-variable.so \
 
 tests += testrunner.so
diff --git a/tests/tst-non-pie.cc b/tests/tst-non-pie.cc
new file mode 100644
index 00000000..be1cf2bf
--- /dev/null
+++ b/tests/tst-non-pie.cc
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(){
+       printf("Hello from C code\n");
+       return 0;
+}
-- 
2.20.1

-- 
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/20190602044503.1419-1-jwkozaczuk%40gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to