| /* |
| * 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 <cinttypes> |
| #include <string> |
| |
| #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<void*>(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 |