LibELF: Make a dummy VM reservation before mapping dynamic objects
Using the text segment for the VM reservation ran into trouble when there was a discrepancy between the p_filesz and p_memsz. Simplify this mechanism and avoid trouble by making the reservation as a MAP_PRIVATE | MAP_NORESERVE throwaway mapping instead. Fixes #5225.
This commit is contained in:
parent
c9cd5ff6bb
commit
3a3270eb68
Notes:
sideshowbarker
2024-07-18 22:36:07 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/3a3270eb682
1 changed files with 22 additions and 15 deletions
|
@ -286,25 +286,38 @@ void DynamicLoader::load_program_headers()
|
|||
|
||||
ASSERT(!text_region.value().is_writable());
|
||||
|
||||
// First, we map the text *and* data segments, in order to allocate enough VM
|
||||
// to hold both contiguously in the address space.
|
||||
// First, we make a dummy reservation mapping, in order to allocate enough VM
|
||||
// to hold both text+data contiguously in the address space.
|
||||
|
||||
Checked<size_t> total_mapping_size;
|
||||
total_mapping_size = text_region.value().required_load_size();
|
||||
total_mapping_size += data_region.value().required_load_size();
|
||||
ASSERT(!total_mapping_size.has_overflow());
|
||||
|
||||
auto* reservation = mmap(requested_load_address, total_mapping_size.value(), PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_NORESERVE, 0, 0);
|
||||
if (reservation == MAP_FAILED) {
|
||||
perror("mmap reservation");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
// Then we unmap the reservation.
|
||||
if (munmap(reservation, total_mapping_size.value()) < 0) {
|
||||
perror("munmap reservation");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
// Now we can map the text segment at the reserved address.
|
||||
auto* text_segment_begin = (u8*)mmap_with_name(
|
||||
requested_load_address,
|
||||
total_mapping_size.value(),
|
||||
reservation,
|
||||
text_region.value().required_load_size(),
|
||||
PROT_READ,
|
||||
text_mmap_flags,
|
||||
m_image_fd,
|
||||
text_region.value().offset(),
|
||||
String::formatted("{}: .text", m_filename).characters());
|
||||
|
||||
if (MAP_FAILED == text_segment_begin) {
|
||||
perror("mmap text / initial segment");
|
||||
if (text_segment_begin == MAP_FAILED) {
|
||||
perror("mmap text");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
@ -312,19 +325,13 @@ void DynamicLoader::load_program_headers()
|
|||
m_text_segment_size = text_region.value().required_load_size();
|
||||
m_text_segment_load_address = VirtualAddress { (FlatPtr)text_segment_begin };
|
||||
|
||||
// Then, we unmap the data segment part of the above combined VM allocation.
|
||||
auto* data_segment_address = (u8*)text_segment_begin + text_region.value().required_load_size();
|
||||
if (munmap(data_segment_address, data_region.value().required_load_size()) < 0) {
|
||||
perror("munmap");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
if (m_elf_image.is_dynamic())
|
||||
m_dynamic_section_address = dynamic_region_desired_vaddr.offset(m_text_segment_load_address.get());
|
||||
else
|
||||
m_dynamic_section_address = dynamic_region_desired_vaddr;
|
||||
|
||||
// Finally, we remap the data segment, this time privately.
|
||||
// Finally, we make an anonymous mapping for the data segment. Contents are then copied from the file.
|
||||
auto* data_segment_address = (u8*)text_segment_begin + text_region.value().required_load_size();
|
||||
auto* data_segment = (u8*)mmap_with_name(
|
||||
data_segment_address,
|
||||
data_region.value().required_load_size(),
|
||||
|
@ -335,7 +342,7 @@ void DynamicLoader::load_program_headers()
|
|||
String::formatted("{}: .data", m_filename).characters());
|
||||
|
||||
if (MAP_FAILED == data_segment) {
|
||||
perror("mmap data segment");
|
||||
perror("mmap data");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue