Skip to content

Commit

Permalink
DynamicLoader+Userland: Enable RELRO for shared libraries as well :^)
Browse files Browse the repository at this point in the history
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! :^)
  • Loading branch information
awesomekling committed Feb 18, 2021
1 parent fa4c249 commit 713b3b3
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 20 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
46 changes: 27 additions & 19 deletions Userland/Libraries/LibELF/DynamicLinker.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, Itamar S. <[email protected]>
* Copyright (c) 2021, Andreas Kling <[email protected]>
* Copyright (c) 2021, the SerenityOS developers.
* All rights reserved.
*
Expand Down Expand Up @@ -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**);
Expand Down Expand Up @@ -178,29 +178,37 @@ static void initialize_libc(DynamicObject& libc)
((libc_init_func*)res.value().address)();
}

static void load_elf(const String& name)
template<typename Callback>
static void for_each_dependency_of_impl(const String& name, HashTable<String>& seen_names, Callback callback)
{
dbgln_if(DYNAMIC_LOAD_DEBUG, "load_elf: {}", name);
auto loader = g_loaders.get(name).value();
if (seen_names.contains(name))
return;
seen_names.set(name);

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);
}
}
for (const auto& needed_name : get_dependencies(name))
for_each_dependency_of_impl(get_library_name(needed_name), seen_names, callback);

bool success = loader->link(RTLD_GLOBAL | RTLD_LAZY, g_total_tls_size);
ASSERT(success);
callback(*g_loaders.get(name).value());
}

g_loaded_objects.set(name, *dynamic_object);
g_global_objects.append(*dynamic_object);
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));
}

dbgln_if(DYNAMIC_LOAD_DEBUG, "load_elf: done {}", name);
static void load_elf(const String& 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)
Expand Down

0 comments on commit 713b3b3

Please sign in to comment.