diff options
author | Gunnar Beutner <gunnar@beutner.name> | 2021-04-16 21:53:43 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-04-18 10:55:25 +0200 |
commit | 6cb28ecee8399b0d79ccfa8b9d58fa04e88846d3 (patch) | |
tree | ce1c0baa4980140034a1f66b4e6f3310c47e9ec2 /Userland | |
parent | cf13fa57cde216b489f6ca1d88e38151151e7c6a (diff) | |
download | serenity-6cb28ecee8399b0d79ccfa8b9d58fa04e88846d3.zip |
LibC+LibELF: Implement support for the dl_iterate_phdr helper
This helper is used by libgcc_s to figure out where the .eh_frame sections
are located for all loaded shared objects.
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/DynamicLoader/main.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibC/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibC/elf.h (renamed from Userland/Libraries/LibELF/exec_elf.h) | 11 | ||||
-rw-r--r-- | Userland/Libraries/LibC/link.cpp | 41 | ||||
-rw-r--r-- | Userland/Libraries/LibC/link.h | 49 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicLinker.cpp | 25 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicLinker.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicLoader.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicLoader.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicObject.cpp | 23 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/DynamicObject.h | 14 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/Image.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/Validation.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibELF/Validation.h | 2 | ||||
-rw-r--r-- | Userland/Tests/Kernel/elf-execve-mmap-race.cpp | 3 | ||||
-rw-r--r-- | Userland/Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp | 3 |
16 files changed, 164 insertions, 22 deletions
diff --git a/Userland/DynamicLoader/main.cpp b/Userland/DynamicLoader/main.cpp index 0f3685b434..3b824451cf 100644 --- a/Userland/DynamicLoader/main.cpp +++ b/Userland/DynamicLoader/main.cpp @@ -66,7 +66,7 @@ static void perform_self_relocations(auxv_t* auxvp) if (!dynamic_section_addr) exit(1); - auto dynamic_object = ELF::DynamicObject::create((VirtualAddress(base_address)), (VirtualAddress(dynamic_section_addr))); + auto dynamic_object = ELF::DynamicObject::create({}, (VirtualAddress(base_address)), (VirtualAddress(dynamic_section_addr))); dynamic_object->relocation_section().for_each_relocation([base_address](auto& reloc) { if (reloc.type() != R_386_RELATIVE) diff --git a/Userland/Libraries/LibC/CMakeLists.txt b/Userland/Libraries/LibC/CMakeLists.txt index 982d578704..d13f6327cc 100644 --- a/Userland/Libraries/LibC/CMakeLists.txt +++ b/Userland/Libraries/LibC/CMakeLists.txt @@ -13,6 +13,7 @@ set(LIBC_SOURCES ioctl.cpp libcinit.cpp libgen.cpp + link.cpp locale.cpp malloc.cpp mman.cpp diff --git a/Userland/Libraries/LibELF/exec_elf.h b/Userland/Libraries/LibC/elf.h index 45a0e9401f..6e3bcf729c 100644 --- a/Userland/Libraries/LibELF/exec_elf.h +++ b/Userland/Libraries/LibC/elf.h @@ -30,10 +30,13 @@ * formerly known as "elf_abi.h". */ -#ifndef _SYS_EXEC_ELF_H_ -#define _SYS_EXEC_ELF_H_ +#pragma once -#include <AK/Types.h> +#ifndef KERNEL +# include <sys/types.h> +#else +# include <AK/Types.h> +#endif typedef uint8_t Elf_Byte; @@ -788,5 +791,3 @@ struct elf_args { #define R_386_RELATIVE 8 /* Base address + Addned */ #define R_386_TLS_TPOFF 14 /* Negative offset into the static TLS storage */ #define R_386_TLS_TPOFF32 37 - -#endif /* _SYS_EXEC_ELF_H_ */ diff --git a/Userland/Libraries/LibC/link.cpp b/Userland/Libraries/LibC/link.cpp new file mode 100644 index 0000000000..3a59e81d6c --- /dev/null +++ b/Userland/Libraries/LibC/link.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, Gunnar Beutner <gunnar@beutner.name> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <link.h> + +extern "C" { + +using DlIteratePhdrCallbackFunction = int (*)(struct dl_phdr_info*, size_t, void*); +using DlIteratePhdrFunction = int (*)(DlIteratePhdrCallbackFunction, void*); + +DlIteratePhdrFunction __dl_iterate_phdr; + +int dl_iterate_phdr(int (*callback)(struct dl_phdr_info* info, size_t size, void* data), void* data) +{ + return __dl_iterate_phdr(callback, data); +} +} diff --git a/Userland/Libraries/LibC/link.h b/Userland/Libraries/LibC/link.h new file mode 100644 index 0000000000..3c667aabd8 --- /dev/null +++ b/Userland/Libraries/LibC/link.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, Gunnar Beutner <gunnar@beutner.name> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#ifndef __serenity__ +# include <LibC/elf.h> +#else +# include <elf.h> +#endif +#include <sys/cdefs.h> + +__BEGIN_DECLS + +#define ElfW(type) Elf32_##type + +struct dl_phdr_info { + Elf32_Addr dlpi_addr; + const char* dlpi_name; + const Elf32_Phdr* dlpi_phdr; + Elf32_Half dlpi_phnum; +}; + +int dl_iterate_phdr(int (*callback)(struct dl_phdr_info* info, size_t size, void* data), void* data); + +__END_DECLS diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp index 56d538155b..de46e2235c 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ b/Userland/Libraries/LibELF/DynamicLinker.cpp @@ -32,6 +32,7 @@ #include <AK/LexicalPath.h> #include <AK/NonnullRefPtrVector.h> #include <AK/ScopeGuard.h> +#include <LibC/link.h> #include <LibC/mman.h> #include <LibC/unistd.h> #include <LibELF/AuxiliaryVector.h> @@ -52,6 +53,8 @@ Vector<NonnullRefPtr<ELF::DynamicObject>> g_global_objects; using EntryPointFunction = int (*)(int, char**, char**); using LibCExitFunction = void (*)(int); +using DlIteratePhdrCallbackFunction = int (*)(struct dl_phdr_info*, size_t, void*); +using DlIteratePhdrFunction = int (*)(DlIteratePhdrCallbackFunction, void*); size_t g_current_tls_offset = 0; size_t g_total_tls_size = 0; @@ -162,6 +165,24 @@ static void allocate_tls() g_total_tls_size = total_tls_size; } +static int __dl_iterate_phdr(DlIteratePhdrCallbackFunction callback, void* data) +{ + for (auto& object : g_global_objects) { + auto info = dl_phdr_info { + .dlpi_addr = (ElfW(Addr))object->base_address().as_ptr(), + .dlpi_name = object->filename().characters(), + .dlpi_phdr = object->program_headers(), + .dlpi_phnum = object->program_header_count() + }; + + auto res = callback(&info, sizeof(info), data); + if (res != 0) + return res; + } + + return 0; +} + static void initialize_libc(DynamicObject& libc) { // Traditionally, `_start` of the main program initializes libc. @@ -181,6 +202,10 @@ static void initialize_libc(DynamicObject& libc) VERIFY(res.has_value()); g_libc_exit = (LibCExitFunction)res.value().address.as_ptr(); + res = libc.lookup_symbol("__dl_iterate_phdr"sv); + VERIFY(res.has_value()); + *((DlIteratePhdrFunction*)res.value().address.as_ptr()) = __dl_iterate_phdr; + res = libc.lookup_symbol("__libc_init"sv); VERIFY(res.has_value()); typedef void libc_init_func(); diff --git a/Userland/Libraries/LibELF/DynamicLinker.h b/Userland/Libraries/LibELF/DynamicLinker.h index 3220953efb..8f73169dab 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.h +++ b/Userland/Libraries/LibELF/DynamicLinker.h @@ -27,7 +27,9 @@ #pragma once #include <AK/Result.h> +#include <AK/String.h> #include <AK/Vector.h> +#include <LibC/link.h> #include <LibELF/DynamicObject.h> namespace ELF { diff --git a/Userland/Libraries/LibELF/DynamicLoader.cpp b/Userland/Libraries/LibELF/DynamicLoader.cpp index 6bd8d69eb7..cfc6e124b8 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.cpp +++ b/Userland/Libraries/LibELF/DynamicLoader.cpp @@ -113,7 +113,7 @@ const DynamicObject& DynamicLoader::dynamic_object() const }); VERIFY(!dynamic_section_address.is_null()); - m_cached_dynamic_object = ELF::DynamicObject::create(VirtualAddress(m_elf_image.base_address()), dynamic_section_address); + m_cached_dynamic_object = ELF::DynamicObject::create(m_filename, VirtualAddress(m_elf_image.base_address()), dynamic_section_address); } return *m_cached_dynamic_object; } @@ -170,7 +170,7 @@ RefPtr<DynamicObject> DynamicLoader::map() VERIFY(!m_base_address.is_null()); - m_dynamic_object = DynamicObject::create(m_base_address, m_dynamic_section_address); + m_dynamic_object = DynamicObject::create(m_filename, m_base_address, m_dynamic_section_address); m_dynamic_object->set_tls_offset(m_tls_offset); m_dynamic_object->set_tls_size(m_tls_size); diff --git a/Userland/Libraries/LibELF/DynamicLoader.h b/Userland/Libraries/LibELF/DynamicLoader.h index 3c3d17533d..25c95902a1 100644 --- a/Userland/Libraries/LibELF/DynamicLoader.h +++ b/Userland/Libraries/LibELF/DynamicLoader.h @@ -31,9 +31,9 @@ #include <AK/OwnPtr.h> #include <AK/RefCounted.h> #include <AK/String.h> +#include <LibC/elf.h> #include <LibELF/DynamicObject.h> #include <LibELF/Image.h> -#include <LibELF/exec_elf.h> #include <sys/mman.h> namespace ELF { diff --git a/Userland/Libraries/LibELF/DynamicObject.cpp b/Userland/Libraries/LibELF/DynamicObject.cpp index 25778fd19a..067069ced8 100644 --- a/Userland/Libraries/LibELF/DynamicObject.cpp +++ b/Userland/Libraries/LibELF/DynamicObject.cpp @@ -28,18 +28,19 @@ #include <AK/Debug.h> #include <AK/String.h> #include <AK/StringBuilder.h> +#include <LibC/elf.h> #include <LibELF/DynamicLoader.h> #include <LibELF/DynamicObject.h> #include <LibELF/Hashes.h> -#include <LibELF/exec_elf.h> #include <string.h> namespace ELF { static const char* name_for_dtag(Elf32_Sword d_tag); -DynamicObject::DynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_address) - : m_base_address(base_address) +DynamicObject::DynamicObject(const String& filename, VirtualAddress base_address, VirtualAddress dynamic_section_address) + : m_filename(filename) + , m_base_address(base_address) , m_dynamic_address(dynamic_section_address) { auto* header = (Elf32_Ehdr*)base_address.as_ptr(); @@ -255,6 +256,18 @@ DynamicObject::RelocationSection DynamicObject::plt_relocation_section() const return RelocationSection(Section(*this, m_plt_relocation_offset_location, m_size_of_plt_relocation_entry_list, m_size_of_relocation_entry, "DT_JMPREL"sv)); } +Elf32_Half DynamicObject::program_header_count() const +{ + auto* header = (const Elf32_Ehdr*)m_base_address.as_ptr(); + return header->e_phnum; +} + +const Elf32_Phdr* DynamicObject::program_headers() const +{ + auto* header = (const Elf32_Ehdr*)m_base_address.as_ptr(); + return (const Elf32_Phdr*)(m_base_address.as_ptr() + header->e_phoff); +} + auto DynamicObject::HashSection::lookup_sysv_symbol(const StringView& name, u32 hash_value) const -> Optional<Symbol> { u32* hash_table_begin = (u32*)address().as_ptr(); @@ -447,9 +460,9 @@ auto DynamicObject::lookup_symbol(const StringView& name, u32 gnu_hash, u32 sysv return SymbolLookupResult { symbol.value(), symbol.address(), symbol.bind(), this }; } -NonnullRefPtr<DynamicObject> DynamicObject::create(VirtualAddress base_address, VirtualAddress dynamic_section_address) +NonnullRefPtr<DynamicObject> DynamicObject::create(const String& filename, VirtualAddress base_address, VirtualAddress dynamic_section_address) { - return adopt(*new DynamicObject(base_address, dynamic_section_address)); + return adopt(*new DynamicObject(filename, base_address, dynamic_section_address)); } // offset is in PLT relocation table diff --git a/Userland/Libraries/LibELF/DynamicObject.h b/Userland/Libraries/LibELF/DynamicObject.h index 8fa50bc18c..ac99504402 100644 --- a/Userland/Libraries/LibELF/DynamicObject.h +++ b/Userland/Libraries/LibELF/DynamicObject.h @@ -29,14 +29,15 @@ #include <AK/Assertions.h> #include <AK/RefCounted.h> +#include <AK/String.h> #include <Kernel/VirtualAddress.h> -#include <LibELF/exec_elf.h> +#include <LibC/elf.h> namespace ELF { class DynamicObject : public RefCounted<DynamicObject> { public: - static NonnullRefPtr<DynamicObject> create(VirtualAddress base_address, VirtualAddress dynamic_section_address); + static NonnullRefPtr<DynamicObject> create(const String& filename, VirtualAddress base_address, VirtualAddress dynamic_section_address); ~DynamicObject(); void dump() const; @@ -238,6 +239,8 @@ public: VirtualAddress plt_got_base_address() const { return m_base_address.offset(m_procedure_linkage_table_offset.value()); } VirtualAddress base_address() const { return m_base_address; } + const String& filename() const { return m_filename; } + StringView rpath() const { return m_has_rpath ? symbol_string_table_string(m_rpath_index) : StringView {}; } StringView runpath() const { return m_has_runpath ? symbol_string_table_string(m_runpath_index) : StringView {}; } StringView soname() const { return m_has_soname ? symbol_string_table_string(m_soname_index) : StringView {}; } @@ -247,6 +250,9 @@ public: void set_tls_offset(FlatPtr offset) { m_tls_offset = offset; } void set_tls_size(FlatPtr size) { m_tls_size = size; } + Elf32_Half program_header_count() const; + const Elf32_Phdr* program_headers() const; + template<typename F> void for_each_needed_library(F) const; @@ -275,12 +281,14 @@ public: bool elf_is_dynamic() const { return m_is_elf_dynamic; } private: - explicit DynamicObject(VirtualAddress base_address, VirtualAddress dynamic_section_address); + explicit DynamicObject(const String& filename, VirtualAddress base_address, VirtualAddress dynamic_section_address); StringView symbol_string_table_string(Elf32_Word) const; const char* raw_symbol_string_table_string(Elf32_Word) const; void parse(); + String m_filename; + VirtualAddress m_base_address; VirtualAddress m_dynamic_address; VirtualAddress m_elf_base_address; diff --git a/Userland/Libraries/LibELF/Image.h b/Userland/Libraries/LibELF/Image.h index 361be1a5c6..326f530ecc 100644 --- a/Userland/Libraries/LibELF/Image.h +++ b/Userland/Libraries/LibELF/Image.h @@ -29,7 +29,7 @@ #include <AK/String.h> #include <AK/Vector.h> #include <Kernel/VirtualAddress.h> -#include <LibELF/exec_elf.h> +#include <LibC/elf.h> namespace ELF { diff --git a/Userland/Libraries/LibELF/Validation.cpp b/Userland/Libraries/LibELF/Validation.cpp index 1336cb91f0..e8cb2b8637 100644 --- a/Userland/Libraries/LibELF/Validation.cpp +++ b/Userland/Libraries/LibELF/Validation.cpp @@ -28,8 +28,8 @@ #include <AK/Assertions.h> #include <AK/Checked.h> #include <AK/String.h> +#include <LibC/elf.h> #include <LibELF/Validation.h> -#include <LibELF/exec_elf.h> namespace ELF { diff --git a/Userland/Libraries/LibELF/Validation.h b/Userland/Libraries/LibELF/Validation.h index e5bc75eff9..ceca8b8173 100644 --- a/Userland/Libraries/LibELF/Validation.h +++ b/Userland/Libraries/LibELF/Validation.h @@ -27,7 +27,7 @@ #pragma once #include <AK/String.h> -#include <LibELF/exec_elf.h> +#include <LibC/elf.h> namespace ELF { diff --git a/Userland/Tests/Kernel/elf-execve-mmap-race.cpp b/Userland/Tests/Kernel/elf-execve-mmap-race.cpp index 002b37fe6f..c63a19e866 100644 --- a/Userland/Tests/Kernel/elf-execve-mmap-race.cpp +++ b/Userland/Tests/Kernel/elf-execve-mmap-race.cpp @@ -24,7 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <LibELF/exec_elf.h> +#include <AK/Types.h> +#include <elf.h> #include <fcntl.h> #include <pthread.h> #include <stdio.h> diff --git a/Userland/Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp b/Userland/Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp index d4ccbf1ac6..6b610cc5fc 100644 --- a/Userland/Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp +++ b/Userland/Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp @@ -24,7 +24,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <LibELF/exec_elf.h> +#include <AK/Types.h> +#include <elf.h> #include <fcntl.h> #include <stdio.h> #include <string.h> |