mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 15:28:11 +00:00
LibELF: Map .text segment with MAP_ANONYMOUS for shared objects
We need to workaround the fact that MAP_PRIVATE when passed a file descriptor doesn't work the way we expect. We can't change the permissions on our mmap to PROT_WRITE if the original executable doesn't have PROT_WRITE. Because of this, we need to construct our ELFDynamicObject using the actual virtual address of the .dynamic section, instead of using the offset into the ELFImage that was actually getting modified by accident ...somehow. Not clear what was going on.
This commit is contained in:
parent
e594724b01
commit
2e349337d3
4 changed files with 26 additions and 18 deletions
|
@ -32,7 +32,8 @@ ELFDynamicLoader::ELFDynamicLoader(const char* filename, int fd, size_t size)
|
|||
{
|
||||
String file_mmap_name = String::format("ELF_DYN: %s", m_filename.characters());
|
||||
|
||||
m_file_mapping = mmap_with_name(nullptr, size, PROT_READ, MAP_PRIVATE, m_image_fd, 0, file_mmap_name.characters());
|
||||
// FIXME: When MAP_PRIVATE is implemented for file-backed regions, change to MAP_PRIVATE
|
||||
m_file_mapping = mmap_with_name(nullptr, size, PROT_READ, MAP_SHARED, m_image_fd, 0, file_mmap_name.characters());
|
||||
if (MAP_FAILED == m_file_mapping) {
|
||||
m_valid = false;
|
||||
}
|
||||
|
@ -64,20 +65,13 @@ bool ELFDynamicLoader::load_from_image(unsigned flags)
|
|||
return false;
|
||||
}
|
||||
|
||||
const ELFImage::DynamicSection probably_dynamic_section = elf_image.dynamic_section();
|
||||
if (StringView(".dynamic") != probably_dynamic_section.name() || probably_dynamic_section.type() != SHT_DYNAMIC) {
|
||||
m_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DYNAMIC_LOAD_VERBOSE
|
||||
m_image->dump();
|
||||
#endif
|
||||
|
||||
load_program_headers(elf_image);
|
||||
|
||||
const ELFImage::DynamicSection image_dynamic_section = elf_image.dynamic_section();
|
||||
m_dynamic_object = AK::make<ELFDynamicObject>(m_text_segment_load_address, image_dynamic_section.offset());
|
||||
m_dynamic_object = AK::make<ELFDynamicObject>(m_text_segment_load_address, m_dynamic_section_address);
|
||||
|
||||
return load_stage_2(flags);
|
||||
}
|
||||
|
@ -94,7 +88,7 @@ bool ELFDynamicLoader::load_stage_2(unsigned flags)
|
|||
if (m_dynamic_object->has_text_relocations()) {
|
||||
ASSERT(m_text_segment_load_address.get() != 0);
|
||||
if (0 > mprotect(m_text_segment_load_address.as_ptr(), m_text_segment_size, PROT_READ | PROT_WRITE)) {
|
||||
perror("mprotect"); // FIXME: dlerror?
|
||||
perror("mprotect .text: PROT_READ | PROT_WRITE"); // FIXME: dlerror?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +99,7 @@ bool ELFDynamicLoader::load_stage_2(unsigned flags)
|
|||
// Clean up our setting of .text to PROT_READ | PROT_WRITE
|
||||
if (m_dynamic_object->has_text_relocations()) {
|
||||
if (0 > mprotect(m_text_segment_load_address.as_ptr(), m_text_segment_size, PROT_READ | PROT_EXEC)) {
|
||||
perror("mprotect"); // FIXME: dlerror?
|
||||
perror("mprotect .text: PROT_READ | PROT_EXEC"); // FIXME: dlerror?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +121,7 @@ void ELFDynamicLoader::load_program_headers(const ELFImage& elf_image)
|
|||
ProgramHeaderRegion* text_region_ptr = nullptr;
|
||||
ProgramHeaderRegion* data_region_ptr = nullptr;
|
||||
ProgramHeaderRegion* tls_region_ptr = nullptr;
|
||||
VirtualAddress dynamic_region_desired_vaddr;
|
||||
|
||||
elf_image.for_each_program_header([&](const ELFImage::ProgramHeader& program_header) {
|
||||
ProgramHeaderRegion new_region;
|
||||
|
@ -143,18 +138,30 @@ void ELFDynamicLoader::load_program_headers(const ELFImage& elf_image)
|
|||
else
|
||||
data_region_ptr = ®ion;
|
||||
}
|
||||
else if (region.is_dynamic()) {
|
||||
dynamic_region_desired_vaddr = region.desired_load_address();
|
||||
}
|
||||
});
|
||||
|
||||
ASSERT(text_region_ptr && data_region_ptr);
|
||||
|
||||
// Process regions in order: .text, .data, .tls
|
||||
auto* region = text_region_ptr;
|
||||
void* text_segment_begin = mmap_with_name(nullptr, region->required_load_size(), region->mmap_prot(), MAP_PRIVATE, m_image_fd, region->offset(), String::format(".text: %s", m_filename.characters()).characters());
|
||||
// FIXME: When MAP_PRIVATE is implemented for file-backed regions, change to MAP_PRIVATE without the mprotect and memcpy
|
||||
//void* text_segment_begin = mmap_with_name(nullptr, region->required_load_size(), region->mmap_prot(), MAP_PRIVATE, m_image_fd, region->offset(), String::format(".text: %s", m_filename.characters()).characters());
|
||||
void* text_segment_begin = mmap_with_name(nullptr, region->required_load_size(), PROT_READ | PROT_WRITE , MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, String::format(".text: %s", m_filename.characters()).characters());
|
||||
if (MAP_FAILED == text_segment_begin) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
m_text_segment_size = region->required_load_size();
|
||||
m_text_segment_load_address = VirtualAddress { (u32)text_segment_begin };
|
||||
memcpy(m_text_segment_load_address.as_ptr(), (u8*)m_file_mapping + region->offset(), region->size_in_image());
|
||||
if (0 > mprotect(text_segment_begin, m_text_segment_size, region->mmap_prot())) {
|
||||
perror("mprotect .text PROT_READ | PROT_EXEC");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
m_dynamic_section_address = dynamic_region_desired_vaddr.offset(m_text_segment_load_address.get());
|
||||
|
||||
region = data_region_ptr;
|
||||
void* data_segment_begin = mmap_with_name((u8*)text_segment_begin + m_text_segment_size, region->required_load_size(), region->mmap_prot(), MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, String::format(".data: %s", m_filename.characters()).characters());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue