/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "berberis/guest_loader/guest_loader.h" #include #include #include "berberis/base/tracing.h" #include "guest_loader_impl.h" // FindSymbol namespace berberis { namespace { android_namespace_t* uninitialized_create_namespace(const char* /* name */, const char* /* ld_library_path */, const char* /* default_library_path */, uint64_t /* type */, const char* /* permitted_when_isolated_path */, android_namespace_t* /* parent_namespace */, const void* /* caller_addr */) { return nullptr; } void* uninitialized_dlopen_ext(const char* /* filename */, int /* flags */, const android_dlextinfo* /* extinfo */, const void* /* caller_addr */) { return nullptr; } bool uninitialized_init_anonymous_namespace(const char* /* shared_libs_sonames */, const char* /* library_search_path */) { return false; } bool uninitialized_link_namespaces(android_namespace_t* /* namespace_from */, android_namespace_t* /* namespace_to */, const char* /* shared_libs_sonames */) { return false; } uintptr_t uninitialized_dl_unwind_find_exidx(uintptr_t /* pc */, int* /* pcount */) { return 0; } int uninitialized_dladdr(const void* /* addr */, Dl_info* /* info */) { return 0; } char* uninitialized_dlerror() { static char error_msg[] = "Linker callbacks are not initialized, likely because " "the loaded executable is a static executable"; return error_msg; } void* uninitialized_dlsym(void* /* handle */, const char* /* symbol */, const void* /* caller_addr */) { return nullptr; } LinkerCallbacks g_uninitialized_callbacks{ .create_namespace_fn_ = uninitialized_create_namespace, .dlopen_ext_fn_ = uninitialized_dlopen_ext, .init_anonymous_namespace_fn_ = uninitialized_init_anonymous_namespace, .link_namespaces_fn_ = uninitialized_link_namespaces, .dl_unwind_find_exidx_fn_ = uninitialized_dl_unwind_find_exidx, .dladdr_fn_ = uninitialized_dladdr, .dlerror_fn_ = uninitialized_dlerror, .dlsym_fn_ = uninitialized_dlsym, }; } // namespace uintptr_t GuestLoader::DlUnwindFindExidx(uintptr_t pc, int* pcount) { TRACE("GuestLoader::DlUnwindFindExidx(pc=%p, pcount=%p)", reinterpret_cast(pc), pcount); return linker_callbacks_.dl_unwind_find_exidx_fn_(pc, pcount); } int GuestLoader::DlAddr(const void* addr, Dl_info* info) { TRACE("GuestLoader::DlAddr(addr=%p, info=%p)", addr, info); // dladdr does *not* set dlerror return linker_callbacks_.dladdr_fn_(addr, info); } void* GuestLoader::DlOpen(const char* libpath, int flags) { TRACE("GuestLoader::DlOpen(libpath=%s, flags=0x%x)", libpath, flags); return DlOpenExt(libpath, flags, nullptr); } void* GuestLoader::DlOpenExt(const char* libpath, int flags, const android_dlextinfo* extinfo) { TRACE("GuestLoader::DlOpen(libpath=\"%s\", flags=0x%x, extinfo=%p)", libpath, flags, extinfo); auto handle = linker_callbacks_.dlopen_ext_fn_(libpath, flags, extinfo, caller_addr_); TRACE("GuestLoader::DlOpen(...) = %p", handle); SetDlErrorIfNeeded(); return handle; } GuestAddr GuestLoader::DlSym(void* handle, const char* name) { TRACE("GuestLoader::DlSym(handle=%p, name=\"%s\")", handle, name); auto* result = linker_callbacks_.dlsym_fn_(handle, name, caller_addr_); SetDlErrorIfNeeded(); return ToGuestAddr(result); } const char* GuestLoader::DlError() { TRACE("GuestLoader::DlError()"); const char* dlerror_msg = dl_error_; dl_error_ = nullptr; return dlerror_msg; } bool GuestLoader::InitAnonymousNamespace(const char* public_ns_sonames, const char* anon_ns_library_path) { TRACE( "GuestLoader::InitAnonymousNamespace(" "public_ns_sonames=\"%s\", " "anon_ns_library_path=\"%s\")", public_ns_sonames, anon_ns_library_path); #if defined(__BIONIC__) SetTargetSdkVersion(android_get_application_target_sdk_version()); #endif bool success = linker_callbacks_.init_anonymous_namespace_fn_(public_ns_sonames, anon_ns_library_path); SetDlErrorIfNeeded(); return success; } android_namespace_t* GuestLoader::CreateNamespace(const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type, const char* permitted_when_isolated_path, android_namespace_t* parent_ns) { TRACE( "GuestLoader::CreateNamespace(" "name=\"%s\", " "ld_library_path=\"%s\", " "default_library_path=\"%s\", " "type=%" PRIx64 ", " "permitted_when_isolated_path=\"%s\", " "parent_ns=%p)", name, ld_library_path, default_library_path, type, permitted_when_isolated_path, parent_ns); #if defined(__BIONIC__) SetTargetSdkVersion(android_get_application_target_sdk_version()); #endif auto result = linker_callbacks_.create_namespace_fn_(name, ld_library_path, default_library_path, type, permitted_when_isolated_path, parent_ns, caller_addr_); TRACE("GuestLoader::CreateNamespace(...) .. = %p", result); SetDlErrorIfNeeded(); return result; } android_namespace_t* GuestLoader::GetExportedNamespace(const char* name) { auto result = linker_callbacks_.get_exported_namespace_fn_(name); TRACE("GuestLoader::GetExportedNamespace(name=\"%s\") = %p", name, result); // Does *not* set dlerror() return result; } bool GuestLoader::LinkNamespaces(android_namespace_t* from, android_namespace_t* to, const char* shared_libs_sonames) { TRACE("GuestLoader::LinkNamespaces(from=%p, to=%p, shared_libs_sonames=\"%s\")", from, to, shared_libs_sonames); bool success = linker_callbacks_.link_namespaces_fn_(from, to, shared_libs_sonames); SetDlErrorIfNeeded(); return success; } void GuestLoader::SetTargetSdkVersion(uint32_t target_sdk_version) { TRACE("GuestLoader::SetTargetSdkVersion(%u)", target_sdk_version); linker_callbacks_.set_application_target_sdk_version_fn_(target_sdk_version); } void GuestLoader::SetDlErrorIfNeeded() { const char* dl_error = linker_callbacks_.dlerror_fn_(); if (dl_error != nullptr) { dl_error_holder_ = dl_error; dl_error_ = dl_error_holder_.c_str(); } } void InitializeLinkerCallbacksToStubs(LinkerCallbacks* linker_callbacks) { *linker_callbacks = g_uninitialized_callbacks; } bool InitializeLinkerCallbacks(LinkerCallbacks* linker_callbacks, const LoadedElfFile& linker_elf_file, std::string* error_msg) { return FindSymbol(linker_elf_file, "__loader_android_create_namespace", &linker_callbacks->create_namespace_fn_, error_msg) && FindSymbol(linker_elf_file, "__loader_android_dlopen_ext", &linker_callbacks->dlopen_ext_fn_, error_msg) && FindSymbol(linker_elf_file, "__loader_android_get_exported_namespace", &linker_callbacks->get_exported_namespace_fn_, error_msg) && FindSymbol(linker_elf_file, "__loader_android_init_anonymous_namespace", &linker_callbacks->init_anonymous_namespace_fn_, error_msg) && FindSymbol(linker_elf_file, "__loader_android_link_namespaces", &linker_callbacks->link_namespaces_fn_, error_msg) && FindSymbol(linker_elf_file, "__loader_android_set_application_target_sdk_version", &linker_callbacks->set_application_target_sdk_version_fn_, error_msg) && FindSymbol(linker_elf_file, "__loader_dladdr", &linker_callbacks->dladdr_fn_, error_msg) && FindSymbol( linker_elf_file, "__loader_dlerror", &linker_callbacks->dlerror_fn_, error_msg) && FindSymbol(linker_elf_file, "__loader_dlsym", &linker_callbacks->dlsym_fn_, error_msg); } } // namespace berberis