Skip to content

Commit

Permalink
LibELF+Userland: Enable RELRO for all userland executables :^)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
awesomekling committed Feb 18, 2021
1 parent 0d3866e commit fa4c249
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 2 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
25 changes: 24 additions & 1 deletion Userland/Libraries/LibELF/DynamicLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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());
Expand All @@ -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;
});
Expand Down Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions Userland/Libraries/LibELF/DynamicLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class DynamicLoader : public RefCounted<DynamicLoader> {
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
Expand Down Expand Up @@ -145,6 +146,9 @@ class DynamicLoader : public RefCounted<DynamicLoader> {
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;

Expand Down
3 changes: 3 additions & 0 deletions Userland/Libraries/LibELF/DynamicObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit fa4c249

Please sign in to comment.