I wonder if that is relevant - https://wiki.ubuntu.com/SecurityTeam/PIE.
In my case when I build native-example hello.c like so (notice absence of -fPIC and -pie): gcc hello.c -o hello I automatically get a pie: file hello hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=a505bb9821b7c033dc777a51fa0c1f0249585e28, not stripped I am sure Nadav can probably provide much better explanation that mine. On Sunday, October 28, 2018 at 4:14:42 PM UTC-4, Waldek Kozaczuk wrote: > > It is my understanding that this patch enhances OSv only as far as > supporting programs using non-fPIC shared libraries. It in no way affects > or changes how OSv handles loading and execution of executables themselves > (ELF with symbol main). > > I guess you are referring to so called non-pie executables that OSv does > not support. I believe there are at least 2 open issues related to this: > > - https://github.com/cloudius-systems/osv/issues/190 > - https://github.com/cloudius-systems/osv/issues/212 > > I am not sure how relevant they are because the main driving force behind > them was Golang support. Given that modern Golang supports generation of > shared libraries and OSv supports running Golang as of release 0.51.0, the > need to execute non-pies is also less and less important. > > BTW I have noticed that on my latest Ubuntu 18.10 distribution programs > like 'ls' and 'grep' seems to be pies as well. > > file hello > hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically > linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, > BuildID[sha1]=e9c4234db3592c18920f9e0eb2d49eecf0fa5e4c, not stripped > > file /bin/ls > /bin/ls: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), > dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux > 3.2.0, BuildID[sha1]=bf40cb84e7815de09fa792a097061886933e56fa, stripped > > When I tried to run unmodified '/bin/ls' on OSv I got this error: > > /ls: failed looking up symbol __progname in other objects > > [backtrace] > 0x000000000034c26b <elf::object::symbol_other(unsigned int)+315> > 0x000000000039f3e0 <elf::object::arch_relocate_rela(unsigned int, unsigned > int, void*, long)+224> > 0x000000000034a5e4 <elf::object::relocate_rela()+148> > 0x000000000034d1d7 <elf::object::relocate()+199> > 0x0000000000350adc > <elf::program::load_object(std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> >, > std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > > >, > std::vector<std::shared_ptr<elf::object>, > std::allocator<std::shared_ptr<elf::object> > >&)+1452> > 0x0000000000351330 > <elf::program::get_library(std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> >, > std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > > >, bool)+336> > 0x000000000042b73b > <osv::application::application(std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > const&, > std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > > > const&, bool, > std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> >, std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> >, > std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > >, > std::allocator<std::pair<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > const, > std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> > > > > const*, std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > const&, > std::function<0x000000000042bfbc > <osv::application::run(std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > const&, > std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > > > const&, bool, > std::unordered_map<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> >, std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> >, > std::hash<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> > >, std::equal_to<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > >, > std::allocator<std::pair<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > const, > std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> > > > > const*, std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> > const&, std::function<void > ()>0x000000000042c22b > <osv::application::run(std::vector<std::__cxx11::basic_string<char, > std::char_traits<char>, std::allocator<char> >, > std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, > std::allocator<char> > > > const&)+91> > 0x0000000000219e06 <do_main_thread(void*)+1942> > 0x0000000000459fb5 <???+4562869> > 0x00000000003f9186 <thread_main_c+38> > 0x000000000039b172 <???+3780978> > > So I wonder how close OSv is to be able to run unmodified Linux > executables like ls and grep as long as they are PIEs. > > Waldek > > On Thursday, October 25, 2018 at 8:22:11 PM UTC-4, Qixuan Wu wrote: >> >> 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]> >>> --- >>> 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.
