summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-02-18 18:43:20 +0100
committerAndreas Kling <kling@serenityos.org>2021-02-18 18:55:19 +0100
commitfa4c249425a65076ca04a3cb0c173d49472796fb (patch)
treee8d201df62b3efad4241992ab33590d687e23357
parent0d3866e84c1a8d4b6024f607ae889071f40c0c3c (diff)
downloadserenity-fa4c249425a65076ca04a3cb0c173d49472796fb.zip
LibELF+Userland: Enable RELRO for all userland executables :^)
The dynamic loader will now mark RELRO segments read-only after performing relocations. This is pretty cool! Note that this only applies to main executables so far,. RELRO support for shared libraries will require some reorganizing of the dynamic loader.
-rw-r--r--CMakeLists.txt2
-rw-r--r--Userland/Libraries/LibELF/DynamicLoader.cpp25
-rw-r--r--Userland/Libraries/LibELF/DynamicLoader.h4
-rw-r--r--Userland/Libraries/LibELF/DynamicObject.cpp3
4 files changed, 32 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 868d584480..80e946a342 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 8b08352a12..af0c945fa0 100644
--- a/Userland/Libraries/LibELF/DynamicLoader.cpp
+++ b/Userland/Libraries/LibELF/DynamicLoader.cpp
@@ -234,6 +234,20 @@ RefPtr<DynamicObject> 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<ProgramHeaderRegion> text_region;
Optional<ProgramHeaderRegion> data_region;
Optional<ProgramHeaderRegion> tls_region;
+ Optional<ProgramHeaderRegion> 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 910dd9882e..33f179d23a 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 999667aa12..14d4eda751 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: