From 713b3b36be4f659e58e253b6c830509898dbd2fa Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 18 Feb 2021 22:49:58 +0100 Subject: [PATCH] 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! :^) --- CMakeLists.txt | 2 +- Userland/Libraries/LibELF/DynamicLinker.cpp | 52 ++++++++++++--------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80e946a3423..d810dd4cc50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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. diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp index b6a0026315a..4c48a6009f2 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ b/Userland/Libraries/LibELF/DynamicLinker.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Itamar S. + * Copyright (c) 2021, Andreas Kling * Copyright (c) 2021, the SerenityOS developers. * All rights reserved. * @@ -50,7 +51,6 @@ namespace ELF { namespace { HashMap> g_loaders; -HashMap> g_loaded_objects; Vector> 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 +static void for_each_dependency_of_impl(const String& name, HashTable& 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 +static void for_each_dependency_of(const String& name, Callback callback) +{ + HashTable 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 commit_elf(const String& name)