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.
+
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*)OSV_KERNEL_VM_BASE)) {
+ // 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;
--
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+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/20190620122108.3549-1-jwkozaczuk%40gmail.com.
For more options, visit https://groups.google.com/d/optout.
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=DW67KbYc5IVwTIMqoOk6/rOXOWO8FcCqwLa8h8mh8/D2KlTg3IeNi2cqc9tqbm/IUNwPuHLnppbny4n9Nfv, not stripped
OSv v0.53.0-36-g99804a6beth0: 192.168.122.15Booted up in 138.79 mspage fault outside application, addr: 0x0000000000400000[registers]RIP: 0x0000000040359a57 <elf::Elf64_Note::Elf64_Note(void*, char*)+39>RFL: 0x0000000000010206 CS: 0x0000000000000008 SS: 0x0000000000000010RAX: 0x0000000000000004 RBX: 0x00002000000ff4f0 RCX: 0x0000000000000000 RDX: 0x0000000000400fa8RSI: 0x0000000000400f9c RDI: 0x00002000000ff4f0 RBP: 0x00002000000ff4a0 R8: 0x00000000409025c0R9: 0x00000000409025c0 R10: 0xffffa00000e54a90 R11: 0x0000000000000001 R12: 0x0000000000400f9cR13: 0x00000000409025c0 R14: 0xffffa00000e54a90 R15: 0x0000000000000001 RSP: 0x00002000000ff460Aborted
[backtrace]0x0000000040349602 <???+1077188098>0x000000004034ae99 <mmu::vm_fault(unsigned long, exception_frame*)+393>0x00000000403a70fd <page_fault+125>0x00000000403a5f76 <???+1077567350>0x000000004035d82e <elf::object::load_segments()+606>0x00000000403608f1 <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> > >&)+1441>0x0000000040361222 <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)+322>0x000000004042f21c <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<0x000000004042f64b <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 ()>0x000000004042f87b <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>0x000000004022df55 <do_main_thread(void*)+2501>0x000000004045d5b5 <???+1078318517>0x0000000040400126 <thread_main_c+38>0x00000000403a6ef2 <???+1077571314>
}
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*)OSV_KERNEL_VM_BASE)) {What is this "base == OSV_KERNEL_VM_BASE case", and why does it fall back to the "else" below?
+ // 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;Why? What is its value before you set it here?
To unsubscribe from this group and stop receiving emails from it, send an email to osv...@googlegroups.com.
On Thursday, June 20, 2019 at 1:15:29 PM UTC-4, Nadav Har'El wrote:- // 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)");
- }I think that we should leave the test but allow either ET_DYN or ET_EXEC, but nothing else.E.g., we don't accept silly things like ".o" files or core files.I don't expect anybody to try this, but since we already have this code, we can fix it instead of remove it.Makes sense. Relatedly is there a way to detect if it is a statically linked executable. Look for missing INTERP segment?
A actually tried to run the golang example with this patch applied built without -pie flag (the default) and it becomes statically linked:
ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=DW67KbYc5IVwTIMqoOk6/rOXOWO8FcCqwLa8h8mh8/D2KlTg3IeNi2cqc9tqbm/IUNwPuHLnppbny4n9Nfv, not stripped
And I get this exception:
OSv v0.53.0-36-g99804a6beth0: 192.168.122.15Booted up in 138.79 mspage fault outside application, addr: 0x0000000000400000[registers]RIP: 0x0000000040359a57 <elf::Elf64_Note::Elf64_Note(void*, char*)+39>
RFL: 0x0000000000010206 CS: 0x0000000000000008 SS: 0x0000000000000010RAX: 0x0000000000000004 RBX: 0x00002000000ff4f0 RCX: 0x0000000000000000 RDX: 0x0000000000400fa8RSI: 0x0000000000400f9c RDI: 0x00002000000ff4f0 RBP: 0x00002000000ff4a0 R8: 0x00000000409025c0R9: 0x00000000409025c0 R10: 0xffffa00000e54a90 R11: 0x0000000000000001 R12: 0x0000000000400f9cR13: 0x00000000409025c0 R14: 0xffffa00000e54a90 R15: 0x0000000000000001 RSP: 0x00002000000ff460Aborted[backtrace]0x0000000040349602 <???+1077188098>0x000000004034ae99 <mmu::vm_fault(unsigned long, exception_frame*)+393>0x00000000403a70fd <page_fault+125>0x00000000403a5f76 <???+1077567350>0x000000004035d82e <elf::object::load_segments()+606>0x00000000403608f1 <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> > >&)+1441>0x0000000040361222 <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)+322>0x000000004042f21c <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<0x000000004042f64b <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 ()>0x000000004042f87b <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>0x000000004022df55 <do_main_thread(void*)+2501>0x000000004045d5b5 <???+1078318517>0x0000000040400126 <thread_main_c+38>0x00000000403a6ef2 <???+1077571314>We should at least catch that we do not support this type of executable
I know we have a problem of missing sbrk syscall per https://github.com/cloudius-systems/osv/issues/212. But golang does not seem to be using it - how does it allocate memory?, maybe through mmap. I see it is using clone() which we do not implement.
+
+ if (is_non_pie_executable() && base != ((void*)OSV_KERNEL_VM_BASE)) {
What is this "base == OSV_KERNEL_VM_BASE case", and why does it fall back to the "else" below?
This is an ugly way to filter out our kernel itself which is an executable as well (set_base is called on loader.elf as well at some point).
+ // 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;Why? What is its value before you set it here?Are you saying this value would be 0 already?
To unsubscribe from this group and stop receiving emails from it, send an email to osv-dev+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/8312547e-9aec-4790-bfac-56dd4f0bae66%40googlegroups.com.