diff options
Diffstat (limited to 'linker/linker_main.cpp')
-rw-r--r-- | linker/linker_main.cpp | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp index 98af54ac2..2a690e9a0 100644 --- a/linker/linker_main.cpp +++ b/linker/linker_main.cpp @@ -31,9 +31,10 @@ #include <link.h> #include <sys/auxv.h> +#include "linker.h" +#include "linker_cfi.h" #include "linker_debug.h" #include "linker_debuggerd.h" -#include "linker_cfi.h" #include "linker_gdb_support.h" #include "linker_globals.h" #include "linker_phdr.h" @@ -66,6 +67,8 @@ static void get_elf_base_from_phdr(const ElfW(Phdr)* phdr_table, size_t phdr_cou static void set_bss_vma_name(soinfo* si); +void __libc_init_mte(const void* phdr_start, size_t phdr_count, uintptr_t load_bias); + // These should be preserved static to avoid emitting // RELATIVE relocations for the part of the code running // before linker links itself. @@ -297,6 +300,13 @@ static ExecutableInfo load_executable(const char* orig_path) { return result; } +static void platform_properties_init() { +#if defined(__aarch64__) + const unsigned long hwcap2 = getauxval(AT_HWCAP2); + g_platform_properties.bti_supported = (hwcap2 & HWCAP2_BTI) != 0; +#endif +} + static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load) { ProtectedDataGuard guard; @@ -311,6 +321,9 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load // Initialize system properties __system_properties_init(); // may use 'environ' + // Initialize platform properties. + platform_properties_init(); + // Register the debuggerd signal handler. linker_debuggerd_init(); @@ -381,6 +394,22 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load solinker->set_realpath(interp); init_link_map_head(*solinker); +#if defined(__aarch64__) + if (exe_to_load == nullptr) { + // Kernel does not add PROT_BTI to executable pages of the loaded ELF. + // Apply appropriate protections here if it is needed. + auto note_gnu_property = GnuPropertySection(somain); + if (note_gnu_property.IsBTICompatible() && + (phdr_table_protect_segments(somain->phdr, somain->phnum, somain->load_bias, + ¬e_gnu_property) < 0)) { + __linker_error("error: can't protect segments for \"%s\": %s", exe_info.path.c_str(), + strerror(errno)); + } + } + + __libc_init_mte(somain->phdr, somain->phnum, somain->load_bias); +#endif + // Register the main executable and the linker upfront to have // gdb aware of them before loading the rest of the dependency // tree. @@ -460,7 +489,6 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load RTLD_GLOBAL, nullptr, true /* add_as_children */, - true /* search_linked_namespaces */, &namespaces)) { __linker_cannot_link(g_argv[0]); } else if (needed_libraries_count == 0) { @@ -698,6 +726,13 @@ __linker_init_post_relocation(KernelArgumentBlock& args, soinfo& tmp_linker_so) // Initialize the linker's own global variables tmp_linker_so.call_constructors(); + // Setting the linker soinfo's soname can allocate heap memory, so delay it until here. + for (const ElfW(Dyn)* d = tmp_linker_so.dynamic; d->d_tag != DT_NULL; ++d) { + if (d->d_tag == DT_SONAME) { + tmp_linker_so.set_soname(tmp_linker_so.get_string(d->d_un.d_val)); + } + } + // When the linker is run directly rather than acting as PT_INTERP, parse // arguments and determine the executable to load. When it's instead acting // as PT_INTERP, AT_ENTRY will refer to the loaded executable rather than the |