/* * Copyright (C) 2019 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. */ #define LOG_TAG "nativeloader" #include "native_loader_namespace.h" #include #include #include #include #include #include "nativeloader/dlext_namespaces.h" using android::base::Error; namespace android { namespace { constexpr const char* kDefaultNamespaceName = "default"; constexpr const char* kSystemNamespaceName = "system"; std::string GetLinkerError(bool is_bridged) { const char* msg = is_bridged ? NativeBridgeGetError() : dlerror(); if (msg == nullptr) { return "no error"; } return std::string(msg); } } // namespace Result NativeLoaderNamespace::GetExportedNamespace(const std::string& name, bool is_bridged) { if (!is_bridged) { auto raw = android_get_exported_namespace(name.c_str()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } else { auto raw = NativeBridgeGetExportedNamespace(name.c_str()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } return Errorf("namespace {} does not exist or exported", name); } // The system namespace is called "default" for binaries in /system and // "system" for those in the Runtime APEX. Try "system" first since // "default" always exists. Result NativeLoaderNamespace::GetSystemNamespace(bool is_bridged) { auto ns = GetExportedNamespace(kSystemNamespaceName, is_bridged); if (ns.ok()) return ns; ns = GetExportedNamespace(kDefaultNamespaceName, is_bridged); if (ns.ok()) return ns; // If nothing is found, return NativeLoaderNamespace constructed from nullptr. // nullptr also means default namespace to the linker. if (!is_bridged) { return NativeLoaderNamespace(kDefaultNamespaceName, static_cast(nullptr)); } else { return NativeLoaderNamespace(kDefaultNamespaceName, static_cast(nullptr)); } } Result NativeLoaderNamespace::Create( const std::string& name, const std::string& search_paths, const std::string& permitted_paths, const NativeLoaderNamespace* parent, bool is_shared, bool is_greylist_enabled, bool also_used_as_anonymous) { bool is_bridged = false; if (parent != nullptr) { is_bridged = parent->IsBridged(); } else if (!search_paths.empty()) { is_bridged = NativeBridgeIsPathSupported(search_paths.c_str()); } // Fall back to the system namespace if no parent is set. auto system_ns = GetSystemNamespace(is_bridged); if (!system_ns.ok()) { return system_ns.error(); } const NativeLoaderNamespace& effective_parent = parent != nullptr ? *parent : *system_ns; // All namespaces for apps are isolated uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED; // The namespace is also used as the anonymous namespace // which is used when the linker fails to determine the caller address if (also_used_as_anonymous) { type |= ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS; } // Bundled apps have access to all system libraries that are currently loaded // in the default namespace if (is_shared) { type |= ANDROID_NAMESPACE_TYPE_SHARED; } if (is_greylist_enabled) { type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED; } if (!is_bridged) { android_namespace_t* raw = android_create_namespace(name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(), effective_parent.ToRawAndroidNamespace()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } else { native_bridge_namespace_t* raw = NativeBridgeCreateNamespace( name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(), effective_parent.ToRawNativeBridgeNamespace()); if (raw != nullptr) { return NativeLoaderNamespace(name, raw); } } return Errorf("failed to create {} namespace name:{}, search_paths:{}, permitted_paths:{}", is_bridged ? "bridged" : "native", name, search_paths, permitted_paths); } Result NativeLoaderNamespace::Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const { LOG_ALWAYS_FATAL_IF(shared_libs.empty(), "empty share lib when linking %s to %s", this->name().c_str(), target.name().c_str()); if (!IsBridged()) { if (android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(), shared_libs.c_str())) { return {}; } } else { if (NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(), target.ToRawNativeBridgeNamespace(), shared_libs.c_str())) { return {}; } } return Error() << GetLinkerError(IsBridged()); } Result NativeLoaderNamespace::Load(const char* lib_name) const { if (!IsBridged()) { android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; extinfo.library_namespace = this->ToRawAndroidNamespace(); void* handle = android_dlopen_ext(lib_name, RTLD_NOW, &extinfo); if (handle != nullptr) { return handle; } } else { void* handle = NativeBridgeLoadLibraryExt(lib_name, RTLD_NOW, this->ToRawNativeBridgeNamespace()); if (handle != nullptr) { return handle; } } return Error() << GetLinkerError(IsBridged()); } } // namespace android