Good news, can we support NON-fPIC elf executable binary ? 

在 2018年10月25日星期四 UTC+8上午6:10:09,Waldek Kozaczuk写道:
>
> This patch enhances ELF dynamic loader to support position 
> dependent shared libraries. It does it by detecting presence 
> of DT_TEXTREL marker and temporarilily making PT_LOAD sections 
> writable so that corresponding references in code get updated 
> to point to correct addresses in memory. Eventually it fixes 
> permissions of PT_LOAD sections to make it non-writable. 
>
> This patch most notably allows to run GraalVM generated 
> Java apps. 
>
> Fixes #1004 
>
> Signed-off-by: Waldemar Kozaczuk <[email protected] <javascript:>> 
> --- 
>  core/elf.cc            | 47 +++++++++++++++++++++++++++++++++++------- 
>  include/osv/elf.hh     |  5 ++++- 
>  modules/tests/Makefile |  9 +++++++- 
>  tests/misc-non-fpic.cc | 13 ++++++++++++ 
>  tests/tst-run.cc       |  3 +++ 
>  5 files changed, 68 insertions(+), 9 deletions(-) 
>  create mode 100644 tests/misc-non-fpic.cc 
>
> diff --git a/core/elf.cc b/core/elf.cc 
> index b0e3c1aa..c0dfbbb9 100644 
> --- a/core/elf.cc 
> +++ b/core/elf.cc 
> @@ -325,13 +325,7 @@ void file::load_segment(const Elf64_Phdr& phdr) 
>      ulong filesz = align_up(filesz_unaligned, mmu::page_size); 
>      ulong memsz = align_up(phdr.p_vaddr + phdr.p_memsz, mmu::page_size) - 
> vstart; 
>   
> -    unsigned perm = 0; 
> -    if (phdr.p_flags & PF_X) 
> -        perm |= mmu::perm_exec; 
> -    if (phdr.p_flags & PF_W) 
> -        perm |= mmu::perm_write; 
> -    if (phdr.p_flags & PF_R) 
> -        perm |= mmu::perm_read; 
> +    unsigned perm = get_segment_mmap_permissions(phdr); 
>   
>      auto flag = mmu::mmap_fixed | (mlocked() ? mmu::mmap_populate : 0); 
>      mmu::map_file(_base + vstart, filesz, flag, perm, _f, 
> align_down(phdr.p_offset, mmu::page_size)); 
> @@ -354,6 +348,11 @@ bool object::mlocked() 
>      return false; 
>  } 
>   
> +bool object::has_non_writable_text_relocations() 
> +{ 
> +    return dynamic_exists(DT_TEXTREL); 
> +} 
> + 
>  Elf64_Note::Elf64_Note(void *_base, char *str) 
>  { 
>      Elf64_Word *base = reinterpret_cast<Elf64_Word *>(_base); 
> @@ -468,8 +467,24 @@ void object::unload_segments() 
>       } 
>  } 
>   
> +unsigned object::get_segment_mmap_permissions(const Elf64_Phdr& phdr) 
> +{ 
> +    unsigned perm = 0; 
> +    if (phdr.p_flags & PF_X) 
> +        perm |= mmu::perm_exec; 
> +    if (phdr.p_flags & PF_W) 
> +        perm |= mmu::perm_write; 
> +    if (phdr.p_flags & PF_R) 
> +        perm |= mmu::perm_read; 
> +    return perm; 
> +} 
> + 
>  void object::fix_permissions() 
>  { 
> +    if(has_non_writable_text_relocations()) { 
> +        make_text_writable(false); 
> +    } 
> + 
>      for (auto&& phdr : _phdrs) { 
>          if (phdr.p_type != PT_GNU_RELRO) 
>              continue; 
> @@ -482,6 +497,20 @@ void object::fix_permissions() 
>      } 
>  } 
>   
> +void object::make_text_writable(bool flag) 
> +{ 
> +    for (auto&& phdr : _phdrs) { 
> +        if (phdr.p_type != PT_LOAD) 
> +            continue; 
> + 
> +        ulong vstart = align_down(phdr.p_vaddr, mmu::page_size); 
> +        ulong memsz = align_up(phdr.p_vaddr + phdr.p_memsz, 
> mmu::page_size) - vstart; 
> + 
> +        unsigned perm = get_segment_mmap_permissions(phdr); 
> +        mmu::mprotect(_base + vstart, memsz, flag ? perm | 
> mmu::perm_write : perm); 
> +    } 
> +} 
> + 
>  template <typename T> 
>  T* object::dynamic_ptr(unsigned tag) 
>  { 
> @@ -600,6 +629,10 @@ symbol_module object::symbol_other(unsigned idx) 
>   
>  void object::relocate_rela() 
>  { 
> +    if(has_non_writable_text_relocations()) { 
> +        make_text_writable(true); 
> +    } 
> + 
>      auto rela = dynamic_ptr<Elf64_Rela>(DT_RELA); 
>      assert(dynamic_val(DT_RELAENT) == sizeof(Elf64_Rela)); 
>      unsigned nb = dynamic_val(DT_RELASZ) / sizeof(Elf64_Rela); 
> diff --git a/include/osv/elf.hh b/include/osv/elf.hh 
> index 5449f98f..19b24eec 100644 
> --- a/include/osv/elf.hh 
> +++ b/include/osv/elf.hh 
> @@ -177,7 +177,7 @@ enum { 
>      DT_PLTREL = 20, // d_val Type of relocation entry used for the 
> procedure linkage 
>        // table. The d_val member contains either DT_REL or DT_RELA. 
>      DT_DEBUG = 21, // d_ptr Reserved for debugger use. 
> -    DT_TEXTREL = 22, // ignored The presence of this dynamic table entry 
> signals that the 
> +    DT_TEXTREL = 22, // The presence of this dynamic table entry signals 
> that the 
>        // relocation table contains relocations for a non-writable 
>        // segment. 
>      DT_JMPREL = 23, // d_ptr Address of the relocations associated with 
> the procedure 
> @@ -367,6 +367,8 @@ protected: 
>      virtual void unload_segment(const Elf64_Phdr& segment) = 0; 
>      virtual void read(Elf64_Off offset, void* data, size_t len) = 0; 
>      bool mlocked(); 
> +    bool has_non_writable_text_relocations(); 
> +    unsigned get_segment_mmap_permissions(const Elf64_Phdr& phdr); 
>  private: 
>      Elf64_Sym* lookup_symbol_old(const char* name); 
>      Elf64_Sym* lookup_symbol_gnu(const char* name); 
> @@ -388,6 +390,7 @@ private: 
>      void collect_dependencies(std::unordered_set<elf::object*>& ds); 
>      void prepare_initial_tls(void* buffer, size_t size, 
> std::vector<ptrdiff_t>& offsets); 
>      void alloc_static_tls(); 
> +    void make_text_writable(bool flag); 
>  protected: 
>      program& _prog; 
>      std::string _pathname; 
> diff --git a/modules/tests/Makefile b/modules/tests/Makefile 
> index cec4febe..0fed7a3b 100644 
> --- a/modules/tests/Makefile 
> +++ b/modules/tests/Makefile 
> @@ -60,6 +60,13 @@ $(out)/tests/rofs/%.o: $(src)/tests/%.c 
>  $(out)/%.so: $(out)/%.o 
>          $(call quiet, $(CXX) $(CXXFLAGS) -shared -o $@ $< $(LIBS), LD 
> $*.so) 
>   
> +NON_FPIC_CXXFLAGS = $(autodepend) $(INCLUDES) -g -O2 -mcmodel=large 
> -fno-pie -DBOOST_TEST_DYN_LINK \ 
> +        -U _FORTIFY_SOURCE -D_KERNEL -D__OSV__ -DCONF_debug_memory=0 \ 
> +        -Wall -Wno-pointer-arith -Wformat=0 -Wno-format-security 
> +$(out)/tests/misc-non-fpic.so: $(src)/tests/misc-non-fpic.cc 
> +        $(makedir) 
> +        $(call quiet, $(CXX) -shared $(NON_FPIC_CXXFLAGS) -o $@ $<, LD 
> $*.so) 
> + 
>  # 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 
>  # and are temporarily removed from the rofs-only-tests list. The tests 
> tst-readdir.so 
> @@ -93,7 +100,7 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so 
> tst-bsd-evh.so \ 
>          misc-tcp-sendonly.so tst-tcp-nbwrite.so misc-tcp-hash-srv.so \ 
>          misc-loadbalance.so misc-scheduler.so tst-console.so tst-app.so \ 
>          misc-setpriority.so misc-timeslice.so misc-tls.so misc-gtod.so \ 
> -        tst-dns-resolver.so tst-kill.so tst-truncate.so \ 
> +        tst-dns-resolver.so tst-kill.so tst-truncate.so misc-non-fpic.so 
> \ 
>          misc-panic.so tst-utimes.so tst-utimensat.so tst-futimesat.so \ 
>          misc-tcp.so tst-strerror_r.so misc-random.so misc-urandom.so \ 
>          tst-commands.so tst-threadcomplete.so tst-timerfd.so \ 
> diff --git a/tests/misc-non-fpic.cc b/tests/misc-non-fpic.cc 
> new file mode 100644 
> index 00000000..77cf17a5 
> --- /dev/null 
> +++ b/tests/misc-non-fpic.cc 
> @@ -0,0 +1,13 @@ 
> +/* 
> + * Copyright (C) 2018 Waldemar Kozaczuk 
> + * 
> + * This work is open source software, licensed under the terms of the 
> + * BSD license as described in the LICENSE file in the top-level 
> directory. 
> + */ 
> +#include <stdio.h> 
> +#include <assert.h> 
> + 
> +int main() { 
> +    printf("Hello\n"); 
> +    assert(1); 
> +} 
> diff --git a/tests/tst-run.cc b/tests/tst-run.cc 
> index 3f1139c3..2d3d6317 100644 
> --- a/tests/tst-run.cc 
> +++ b/tests/tst-run.cc 
> @@ -48,6 +48,9 @@ int main(int ac, char** av) 
>          report(true, "Run nonexistant"); 
>      } 
>   
> +    b = (bool)osv::run("/tests/misc-non-fpic.so", 0, nullptr, nullptr); 
> +    report(b == true, "Run non-PIC with non-writable relocations"); 
> + 
>      return 0; 
>  } 
>   
> -- 
> 2.17.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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to