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

Allow running non-PIE executables that do not collide with kernel

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

Fixes #190

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
Message-Id: <20190621040947.29711-1-jwkozac...@gmail.com>

---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -312,7 +312,8 @@ gcc-sysroot = $(if $(CROSS_PREFIX), --sysroot external/$(arch)/gcc.bin) \
 # To add something that will *not* be part of the main kernel, you can do:
 #
 #   mydir/*.o EXTRA_FLAGS = <MY_STUFF>
-EXTRA_FLAGS = -D__OSV_CORE__ -DOSV_KERNEL_BASE=$(kernel_base) -DOSV_KERNEL_VM_SHIFT=$(kernel_vm_shift) -DOSV_LZKERNEL_BASE=$(lzkernel_base) +EXTRA_FLAGS = -D__OSV_CORE__ -DOSV_KERNEL_BASE=$(kernel_base) -DOSV_KERNEL_VM_BASE=$(kernel_vm_base) \ + -DOSV_KERNEL_VM_SHIFT=$(kernel_vm_shift) -DOSV_LZKERNEL_BASE=$(lzkernel_base)
 EXTRA_LIBS =
COMMON = $(autodepend) -g -Wall -Wno-pointer-arith $(CFLAGS_WERROR) -Wformat=0 -Wno-format-security \
        -D __BSD_VISIBLE=1 -U _FORTIFY_SOURCE -fno-stack-protector $(INCLUDES) \
diff --git a/core/elf.cc b/core/elf.cc
--- 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 {
@@ -224,7 +227,6 @@ memory_image::memory_image(program& prog, void* base)
     auto p = static_cast<Elf64_Phdr*>(base + _ehdr.e_phoff);
     assert(_ehdr.e_phentsize == sizeof(*p));
     _phdrs.assign(p, p + _ehdr.e_phnum);
-    set_base(base);
 }

 void memory_image::load_segment(const Elf64_Phdr& phdr)
@@ -267,14 +269,9 @@ 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) {
+    if (!(_ehdr.e_type == ET_DYN || _ehdr.e_type == ET_EXEC)) {
         throw osv::invalid_elf_error(
- "bad executable type (only shared-object or PIE supported)"); + "bad executable type (only shared-object, PIE or non-PIE executable supported)");
     }
 }

@@ -297,17 +294,37 @@ 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_core() && is_non_pie_executable()) {
+        // 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);
+        }
+ // Override the passed in value as the base for non-PIEs (Position Dependant Executables) + // needs to be set to 0 because all the addresses in it are absolute
+        _base = 0x0;
+    } else {
+ // Otherwise for kernel, PIEs and shared libraries set the base as requested by caller + _base = align(base, p->p_align, p->p_vaddr & (p->p_align - 1)) - p->p_vaddr;
+    }
+
     _end = _base + q->p_vaddr + q->p_memsz;
 }

@@ -447,6 +464,9 @@ void object::load_segments()
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");
+    }
     // As explained in issue #352, we currently don't correctly support TLS
     // used in PIEs.
     if (_is_executable && _tls_segment) {
@@ -1099,7 +1119,9 @@ void create_main_program()
 program::program(void* addr)
     : _next_alloc(addr)
 {
- _core = std::make_shared<memory_image>(*this, (void*)(ELF_IMAGE_START + OSV_KERNEL_VM_SHIFT));
+    void *program_base = (void*)(ELF_IMAGE_START + OSV_KERNEL_VM_SHIFT);
+    _core = std::make_shared<memory_image>(*this, program_base);
+    _core->set_base(program_base);
     assert(_core->module_index() == core_module_index);
     _core->load_segments();
     set_search_path({"/", "/usr/lib"});
@@ -1223,7 +1245,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
--- 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
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -67,7 +67,11 @@ $(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 $@)
+
+$(out)/tests/tst-non-pie.so: CXXFLAGS:=$(subst -fPIC,-no-pie,$(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 +128,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
--- a/tests/tst-non-pie.cc
+++ b/tests/tst-non-pie.cc
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(){
+       printf("Hello from C code\n");
+       return 0;
+}

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

Reply via email to