blob: 2661c7bce656bac143458373466353de18cc847a [file] [log] [blame]
/*
* 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