DynamicLoader+Userland: Enable RELRO for shared libraries as well :^)

To support this, I had to reorganize the "load_elf" function into two
passes. First we map all the dynamic objects, to get their symbols
into the global lookup table. Then we link all the dynamic objects.

So many read-only GOT's! :^)
This commit is contained in:
Andreas Kling 2021-02-18 22:49:58 +01:00
parent fa4c249425
commit 713b3b36be
2 changed files with 31 additions and 23 deletions

View file

@ -146,7 +146,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_SHARED_LIBRARY_CREATE_CXX_FLAGS "-shared -Wl,--hash-style=gnu,-z,relro,-z,now")
set(CMAKE_CXX_LINK_FLAGS "-Wl,--hash-style=gnu,-z,relro,-z,now")
# We disable it completely because it makes cmake very spammy.

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, the SerenityOS developers.
* All rights reserved.
*
@ -50,7 +51,6 @@ namespace ELF {
namespace {
HashMap<String, NonnullRefPtr<ELF::DynamicLoader>> g_loaders;
HashMap<String, NonnullRefPtr<ELF::DynamicObject>> g_loaded_objects;
Vector<NonnullRefPtr<ELF::DynamicObject>> g_global_objects;
using MainFunction = int (*)(int, char**, char**);
@ -178,29 +178,37 @@ static void initialize_libc(DynamicObject& libc)
((libc_init_func*)res.value().address)();
}
template<typename Callback>
static void for_each_dependency_of_impl(const String& name, HashTable<String>& seen_names, Callback callback)
{
if (seen_names.contains(name))
return;
seen_names.set(name);
for (const auto& needed_name : get_dependencies(name))
for_each_dependency_of_impl(get_library_name(needed_name), seen_names, callback);
callback(*g_loaders.get(name).value());
}
template<typename Callback>
static void for_each_dependency_of(const String& name, Callback callback)
{
HashTable<String> seen_names;
for_each_dependency_of_impl(name, seen_names, move(callback));
}
static void load_elf(const String& name)
{
dbgln_if(DYNAMIC_LOAD_DEBUG, "load_elf: {}", name);
auto loader = g_loaders.get(name).value();
auto dynamic_object = loader->map();
ASSERT(dynamic_object);
for (const auto& needed_name : get_dependencies(name)) {
dbgln_if(DYNAMIC_LOAD_DEBUG, "needed library: {}", needed_name);
String library_name = get_library_name(needed_name);
if (!g_loaded_objects.contains(library_name)) {
load_elf(library_name);
}
}
bool success = loader->link(RTLD_GLOBAL | RTLD_LAZY, g_total_tls_size);
ASSERT(success);
g_loaded_objects.set(name, *dynamic_object);
g_global_objects.append(*dynamic_object);
dbgln_if(DYNAMIC_LOAD_DEBUG, "load_elf: done {}", name);
for_each_dependency_of(name, [](auto& loader) {
auto dynamic_object = loader.map();
ASSERT(dynamic_object);
g_global_objects.append(*dynamic_object);
});
for_each_dependency_of(name, [](auto& loader) {
bool success = loader.link(RTLD_GLOBAL | RTLD_LAZY, g_total_tls_size);
ASSERT(success);
});
}
static NonnullRefPtr<DynamicLoader> commit_elf(const String& name)