diff --git a/Userland/Libraries/LibC/dlfcn.cpp b/Userland/Libraries/LibC/dlfcn.cpp index e5eecdfbf8..ed4a400007 100644 --- a/Userland/Libraries/LibC/dlfcn.cpp +++ b/Userland/Libraries/LibC/dlfcn.cpp @@ -11,10 +11,10 @@ #include // These are filled in by the dynamic loader. -DlCloseFunction __dlclose; -DlOpenFunction __dlopen; -DlSymFunction __dlsym; -DlAddrFunction __dladdr; +[[gnu::weak]] DlCloseFunction __dlclose; +[[gnu::weak]] DlOpenFunction __dlopen; +[[gnu::weak]] DlSymFunction __dlsym; +[[gnu::weak]] DlAddrFunction __dladdr; // FIXME: use thread_local and a String once TLS works #ifdef NO_TLS diff --git a/Userland/Libraries/LibC/libcinit.cpp b/Userland/Libraries/LibC/libcinit.cpp index e1024acfd9..dabe2d3d2c 100644 --- a/Userland/Libraries/LibC/libcinit.cpp +++ b/Userland/Libraries/LibC/libcinit.cpp @@ -17,8 +17,8 @@ int errno_storage; #else __thread int errno_storage; #endif -char** environ; -bool __environ_is_malloced; +[[gnu::weak]] char** environ; +bool __environ_is_malloced = false; bool __stdio_is_initialized; void* __auxiliary_vector; diff --git a/Userland/Libraries/LibC/link.cpp b/Userland/Libraries/LibC/link.cpp index 84397eb687..f686ae18fc 100644 --- a/Userland/Libraries/LibC/link.cpp +++ b/Userland/Libraries/LibC/link.cpp @@ -12,7 +12,7 @@ extern "C" { using DlIteratePhdrCallbackFunction = int (*)(struct dl_phdr_info*, size_t, void*); using DlIteratePhdrFunction = int (*)(DlIteratePhdrCallbackFunction, void*); -DlIteratePhdrFunction __dl_iterate_phdr; +[[gnu::weak]] DlIteratePhdrFunction __dl_iterate_phdr; int dl_iterate_phdr(int (*callback)(struct dl_phdr_info* info, size_t size, void* data), void* data) { diff --git a/Userland/Libraries/LibC/ssp.cpp b/Userland/Libraries/LibC/ssp.cpp index 126a946b86..734ca7c561 100644 --- a/Userland/Libraries/LibC/ssp.cpp +++ b/Userland/Libraries/LibC/ssp.cpp @@ -18,8 +18,8 @@ extern "C" { extern uintptr_t __stack_chk_guard; -// Initialized in `initialize_libc` (we leave a placeholder value here before initialization). -__attribute__((used)) uintptr_t __stack_chk_guard = (uintptr_t)0xc6c7c8c9; +// Populated by DynamicLinker in shared executables. +[[gnu::weak]] uintptr_t __stack_chk_guard = (uintptr_t)0xc6c7c8c9; __attribute__((noreturn)) void __stack_chk_fail() { diff --git a/Userland/Libraries/LibC/stdlib.cpp b/Userland/Libraries/LibC/stdlib.cpp index 29325d555b..76ea655e4e 100644 --- a/Userland/Libraries/LibC/stdlib.cpp +++ b/Userland/Libraries/LibC/stdlib.cpp @@ -345,7 +345,7 @@ static T c_str_to_floating_point(char const* str, char** endptr) extern "C" { -void (*__call_fini_functions)(); +[[gnu::weak]] void (*__call_fini_functions)(); void exit(int status) { diff --git a/Userland/Libraries/LibELF/DynamicLinker.cpp b/Userland/Libraries/LibELF/DynamicLinker.cpp index e00f1fe3cb..191f5565c1 100644 --- a/Userland/Libraries/LibELF/DynamicLinker.cpp +++ b/Userland/Libraries/LibELF/DynamicLinker.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,6 @@ static size_t s_current_tls_offset = 0; static size_t s_total_tls_size = 0; static size_t s_allocated_tls_block_size = 0; static char** s_envp = nullptr; -static LibCExitFunction s_libc_exit = nullptr; static __pthread_mutex_t s_loader_lock = __PTHREAD_MUTEX_INITIALIZER; static ByteString s_cwd; @@ -65,11 +65,32 @@ static StringView s_ld_library_path; static StringView s_main_program_pledge_promises; static ByteString s_loader_pledge_promises; -static Result __dlclose(void* handle); -static Result __dlopen(char const* filename, int flags); -static Result __dlsym(void* handle, char const* symbol_name); -static Result __dladdr(void const* addr, Dl_info* info); -static void __call_fini_functions(); +class MagicWeakSymbol : public RefCounted { + AK_MAKE_NONCOPYABLE(MagicWeakSymbol); + AK_MAKE_NONMOVABLE(MagicWeakSymbol); + +public: + template + MagicWeakSymbol(unsigned int type, T value) + { + m_storage = reinterpret_cast(value); + m_lookup_result.size = 8; + m_lookup_result.type = type; + m_lookup_result.address = VirtualAddress { &m_storage }; + m_lookup_result.bind = STB_GLOBAL; + } + + auto lookup_result() const + { + return m_lookup_result; + } + +private: + DynamicObject::SymbolLookupResult m_lookup_result; + uintptr_t m_storage; +}; + +static HashMap> s_magic_weak_symbols; Optional DynamicLinker::lookup_global_symbol(StringView name) { @@ -87,6 +108,10 @@ Optional DynamicLinker::lookup_global_symbol( weak_result = res; // We don't want to allow local symbols to be pulled in to other modules } + + if (auto magic_lookup = s_magic_weak_symbols.get(name); magic_lookup.has_value()) + weak_result = (*magic_lookup)->lookup_result(); + return weak_result; } @@ -260,61 +285,7 @@ static int __dl_iterate_phdr(DlIteratePhdrCallbackFunction callback, void* data) static void initialize_libc(DynamicObject& libc) { - // Traditionally, `_start` of the main program initializes libc. - // However, since some libs use malloc() and getenv() in global constructors, - // we have to initialize libc just after it is loaded. - // Also, we can't just mark `__libc_init` with "__attribute__((constructor))" - // because it uses getenv() internally, so `environ` has to be initialized before we call `__libc_init`. - auto res = libc.lookup_symbol("environ"sv); - VERIFY(res.has_value()); - *((char***)res.value().address.as_ptr()) = s_envp; - - // __stack_chk_guard should be initialized before anything significant (read: global constructors) is running. - // This is not done in __libc_init, as we definitely have to return from that, and it might affect Loader as well. - res = libc.lookup_symbol("__stack_chk_guard"sv); - VERIFY(res.has_value()); - void* stack_guard = res.value().address.as_ptr(); - arc4random_buf(stack_guard, sizeof(uintptr_t)); - -#ifdef AK_ARCH_64_BIT - // For 64-bit platforms we include an additional hardening: zero the first byte of the stack guard to avoid - // leaking or overwriting the stack guard with C-style string functions. - ((char*)stack_guard)[0] = 0; -#endif - - res = libc.lookup_symbol("__environ_is_malloced"sv); - VERIFY(res.has_value()); - *((bool*)res.value().address.as_ptr()) = false; - - res = libc.lookup_symbol("exit"sv); - VERIFY(res.has_value()); - s_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("__dlclose"sv); - VERIFY(res.has_value()); - *((DlCloseFunction*)res.value().address.as_ptr()) = __dlclose; - - res = libc.lookup_symbol("__dlopen"sv); - VERIFY(res.has_value()); - *((DlOpenFunction*)res.value().address.as_ptr()) = __dlopen; - - res = libc.lookup_symbol("__dlsym"sv); - VERIFY(res.has_value()); - *((DlSymFunction*)res.value().address.as_ptr()) = __dlsym; - - res = libc.lookup_symbol("__dladdr"sv); - VERIFY(res.has_value()); - *((DlAddrFunction*)res.value().address.as_ptr()) = __dladdr; - - res = libc.lookup_symbol("__call_fini_functions"sv); - VERIFY(res.has_value()); - *((CallFiniFunctionsFunction*)res.value().address.as_ptr()) = __call_fini_functions; - - res = libc.lookup_symbol("__libc_init"sv); + auto res = libc.lookup_symbol("__libc_init"sv); VERIFY(res.has_value()); typedef void libc_init_func(); ((libc_init_func*)res.value().address.as_ptr())(); @@ -662,6 +633,23 @@ void ELF::DynamicLinker::linker_main(ByteString&& main_program_path, int main_pr s_envp = envp; + uintptr_t stack_guard = get_random(); + +#ifdef AK_ARCH_64_BIT + // For 64-bit platforms we include an additional hardening: zero the first byte of the stack guard to avoid + // leaking or overwriting the stack guard with C-style string functions. + stack_guard &= ~0xffULL; +#endif + + s_magic_weak_symbols.set("environ"sv, make_ref_counted(STT_OBJECT, s_envp)); + s_magic_weak_symbols.set("__stack_chk_guard"sv, make_ref_counted(STT_OBJECT, stack_guard)); + s_magic_weak_symbols.set("__call_fini_functions"sv, make_ref_counted(STT_FUNC, __call_fini_functions)); + s_magic_weak_symbols.set("__dl_iterate_phdr"sv, make_ref_counted(STT_FUNC, __dl_iterate_phdr)); + s_magic_weak_symbols.set("__dlclose"sv, make_ref_counted(STT_FUNC, __dlclose)); + s_magic_weak_symbols.set("__dlopen"sv, make_ref_counted(STT_FUNC, __dlopen)); + s_magic_weak_symbols.set("__dlsym"sv, make_ref_counted(STT_FUNC, __dlsym)); + s_magic_weak_symbols.set("__dladdr"sv, make_ref_counted(STT_FUNC, __dladdr)); + char* raw_current_directory = getcwd(nullptr, 0); s_cwd = raw_current_directory; free(raw_current_directory);