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 <jwkoz...@gmail.com <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 osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to