diff --git a/CMakeLists.txt b/CMakeLists.txt index 868d5844807..80e946a3423 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,7 +147,7 @@ endforeach() set(CMAKE_INSTALL_NAME_TOOL "") set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-shared -Wl,--hash-style=gnu") -set(CMAKE_CXX_LINK_FLAGS "-Wl,--hash-style=gnu") +set(CMAKE_CXX_LINK_FLAGS "-Wl,--hash-style=gnu,-z,relro,-z,now") # We disable it completely because it makes cmake very spammy. # This will need to be revisited when the Loader supports RPATH/RUN_PATH. diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp index 8b08352a12f..af0c945fa0c 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.cpp +++ b/Userland/Libraries/LibELF/DynamicLoader.cpp @@ -234,6 +234,20 @@ RefPtr DynamicLoader::load_stage_3(unsigned flags, size_t total_t return nullptr; } + if (m_relro_segment_size) { + if (mprotect(m_relro_segment_address.as_ptr(), m_relro_segment_size, PROT_READ) < 0) { + perror("mprotect .relro: PROT_READ"); + return nullptr; + } + +#if __serenity__ + if (set_mmap_name(m_relro_segment_address.as_ptr(), m_relro_segment_size, String::formatted("{}: .relro", m_filename).characters()) < 0) { + perror("set_mmap_name .relro"); + return nullptr; + } +#endif + } + call_object_init_functions(); dbgln_if(DYNAMIC_LOAD_DEBUG, "Loaded {}", m_filename); @@ -255,11 +269,12 @@ void DynamicLoader::load_program_headers() Optional text_region; Optional data_region; Optional tls_region; + Optional relro_region; VirtualAddress dynamic_region_desired_vaddr; m_elf_image.for_each_program_header([&](const Image::ProgramHeader& program_header) { - ProgramHeaderRegion region; + ProgramHeaderRegion region {}; region.set_program_header(program_header.raw_header()); if (region.is_tls_template()) { ASSERT(!tls_region.has_value()); @@ -274,6 +289,9 @@ void DynamicLoader::load_program_headers() } } else if (region.is_dynamic()) { dynamic_region_desired_vaddr = region.desired_load_address(); + } else if (region.is_relro()) { + ASSERT(!relro_region.has_value()); + relro_region = region; } return IterationDecision::Continue; }); @@ -336,6 +354,11 @@ void DynamicLoader::load_program_headers() m_text_segment_size = text_segment_size; m_text_segment_load_address = VirtualAddress { (FlatPtr)text_segment_begin }; + if (relro_region.has_value()) { + m_relro_segment_size = relro_region->size_in_memory(); + m_relro_segment_address = m_text_segment_load_address.offset(relro_region->desired_load_address().get()); + } + if (m_elf_image.is_dynamic()) m_dynamic_section_address = dynamic_region_desired_vaddr.offset(m_text_segment_load_address.get()); else diff --git a/Userland/Libraries/LibELF/DynamicLoader.h b/Userland/Libraries/LibELF/DynamicLoader.h index 910dd9882e4..33f179d23a1 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.h +++ b/Userland/Libraries/LibELF/DynamicLoader.h @@ -102,6 +102,7 @@ private: bool is_tls_template() const { return type() == PT_TLS; } bool is_load() const { return type() == PT_LOAD; } bool is_dynamic() const { return type() == PT_DYNAMIC; } + bool is_relro() const { return type() == PT_GNU_RELRO; } private: Elf32_Phdr m_program_header; // Explicitly a copy of the PHDR in the image @@ -145,6 +146,9 @@ private: VirtualAddress m_text_segment_load_address; size_t m_text_segment_size { 0 }; + VirtualAddress m_relro_segment_address; + size_t m_relro_segment_size { 0 }; + VirtualAddress m_tls_segment_address; VirtualAddress m_dynamic_section_address; diff --git a/Userland/Libraries/LibELF/DynamicObject.cpp b/Userland/Libraries/LibELF/DynamicObject.cpp index 999667aa126..14d4eda7517 100644 --- a/Userland/Libraries/LibELF/DynamicObject.cpp +++ b/Userland/Libraries/LibELF/DynamicObject.cpp @@ -160,6 +160,9 @@ void DynamicObject::parse() m_soname_index = entry.val(); m_has_soname = true; break; + case DT_BIND_NOW: + m_dt_flags |= DF_BIND_NOW; + break; case DT_DEBUG: break; case DT_FLAGS_1: