diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp index 3b77a9e9f..debc43f70 100644 --- a/libnativeloader/Android.bp +++ b/libnativeloader/Android.bp @@ -30,6 +30,7 @@ cc_library { android: { srcs: [ "library_namespaces.cpp", + "native_loader_namespace.cpp", "public_libraries.cpp", ], shared_libs: [ diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index 3839a15fa..1900d5d71 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -41,8 +41,6 @@ namespace { // vendor and system namespaces. constexpr const char* kVendorNamespaceName = "sphal"; constexpr const char* kVndkNamespaceName = "vndk"; -constexpr const char* kDefaultNamespaceName = "default"; -constexpr const char* kPlatformNamespaceName = "platform"; constexpr const char* kRuntimeNamespaceName = "runtime"; // classloader-namespace is a linker namespace that is created for the loaded @@ -167,34 +165,13 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader"); - uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED; - if (is_shared) { - namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED; - } - - if (target_sdk_version < 24) { - namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED; - } - - NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader); - - bool is_native_bridge = false; - - if (parent_ns != nullptr) { - is_native_bridge = !parent_ns->is_android_namespace(); - } else if (!library_path.empty()) { - is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str()); - } - std::string system_exposed_libraries = default_public_libraries(); const char* namespace_name = kClassloaderNamespaceName; - android_namespace_t* vndk_ns = nullptr; + bool unbundled_vendor_or_product_app = false; if ((apk_origin == APK_ORIGIN_VENDOR || (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) && !is_shared) { - LOG_FATAL_IF(is_native_bridge, - "Unbundled vendor / product apk must not use translated architecture"); - + unbundled_vendor_or_product_app = true; // For vendor / product apks, give access to the vendor / product lib even though // they are treated as unbundled; the libs and apks are still bundled // together in the vendor / product partition. @@ -214,22 +191,12 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd origin_partition = "unknown"; origin_lib_path = ""; } - - LOG_FATAL_IF(is_native_bridge, "Unbundled %s apk must not use translated architecture", - origin_partition); - library_path = library_path + ":" + origin_lib_path; permitted_path = permitted_path + ":" + origin_lib_path; // Also give access to LLNDK libraries since they are available to vendors system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries().c_str(); - // Give access to VNDK-SP libraries from the 'vndk' namespace. - vndk_ns = android_get_exported_namespace(kVndkNamespaceName); - if (vndk_ns == nullptr) { - ALOGW("Cannot find \"%s\" namespace for %s apks", kVndkNamespaceName, origin_partition); - } - // Different name is useful for debugging namespace_name = kVendorClassloaderNamespaceName; ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s", @@ -241,120 +208,56 @@ NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sd system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries(); } } - std::string runtime_exposed_libraries = runtime_public_libraries(); - NativeLoaderNamespace native_loader_ns; - if (!is_native_bridge) { - // The platform namespace is called "default" for binaries in /system and - // "platform" for those in the Runtime APEX. Try "platform" first since - // "default" always exists. - android_namespace_t* platform_ns = android_get_exported_namespace(kPlatformNamespaceName); - if (platform_ns == nullptr) { - platform_ns = android_get_exported_namespace(kDefaultNamespaceName); - } - - android_namespace_t* android_parent_ns; - if (parent_ns != nullptr) { - android_parent_ns = parent_ns->get_android_ns(); - } else { - // Fall back to the platform namespace if no parent is found. - android_parent_ns = platform_ns; - } - - android_namespace_t* ns = - android_create_namespace(namespace_name, nullptr, library_path.c_str(), namespace_type, - permitted_path.c_str(), android_parent_ns); - if (ns == nullptr) { - *error_msg = dlerror(); - return nullptr; - } - - // Note that when vendor_ns is not configured this function will return nullptr - // and it will result in linking vendor_public_libraries_ to the default namespace - // which is expected behavior in this case. - android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName); - - android_namespace_t* runtime_ns = android_get_exported_namespace(kRuntimeNamespaceName); - - if (!android_link_namespaces(ns, platform_ns, system_exposed_libraries.c_str())) { - *error_msg = dlerror(); - return nullptr; - } - - // Runtime apex does not exist in host, and under certain build conditions. - if (runtime_ns != nullptr) { - if (!android_link_namespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) { - *error_msg = dlerror(); - return nullptr; - } - } - - if (vndk_ns != nullptr && !vndksp_libraries().empty()) { - // vendor apks are allowed to use VNDK-SP libraries. - if (!android_link_namespaces(ns, vndk_ns, vndksp_libraries().c_str())) { - *error_msg = dlerror(); - return nullptr; - } - } - - if (!vendor_public_libraries().empty()) { - if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries().c_str())) { - *error_msg = dlerror(); - return nullptr; - } - } - - native_loader_ns = NativeLoaderNamespace(ns); - } else { - // Same functionality as in the branch above, but calling through native bridge. - - native_bridge_namespace_t* platform_ns = - NativeBridgeGetExportedNamespace(kPlatformNamespaceName); - if (platform_ns == nullptr) { - platform_ns = NativeBridgeGetExportedNamespace(kDefaultNamespaceName); - } - - native_bridge_namespace_t* native_bridge_parent_namespace; - if (parent_ns != nullptr) { - native_bridge_parent_namespace = parent_ns->get_native_bridge_ns(); - } else { - native_bridge_parent_namespace = platform_ns; - } - - native_bridge_namespace_t* ns = - NativeBridgeCreateNamespace(namespace_name, nullptr, library_path.c_str(), namespace_type, - permitted_path.c_str(), native_bridge_parent_namespace); - if (ns == nullptr) { - *error_msg = NativeBridgeGetError(); - return nullptr; - } - - native_bridge_namespace_t* vendor_ns = NativeBridgeGetExportedNamespace(kVendorNamespaceName); - native_bridge_namespace_t* runtime_ns = NativeBridgeGetExportedNamespace(kRuntimeNamespaceName); - - if (!NativeBridgeLinkNamespaces(ns, platform_ns, system_exposed_libraries.c_str())) { - *error_msg = NativeBridgeGetError(); - return nullptr; - } - - // Runtime apex does not exist in host, and under certain build conditions. - if (runtime_ns != nullptr) { - if (!NativeBridgeLinkNamespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) { - *error_msg = NativeBridgeGetError(); - return nullptr; - } - } - if (!vendor_public_libraries().empty()) { - if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries().c_str())) { - *error_msg = NativeBridgeGetError(); - return nullptr; - } - } - - native_loader_ns = NativeLoaderNamespace(ns); + // Create the app namespace + NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader); + auto app_ns = + NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns, + is_shared, target_sdk_version < 24 /* is_greylist_enabled */); + if (app_ns.IsNil()) { + *error_msg = app_ns.GetError(); + return nullptr; } - namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns)); + // ... and link to other namespaces to allow access to some public libraries + bool is_bridged = app_ns.IsBridged(); + + auto platform_ns = NativeLoaderNamespace::GetPlatformNamespace(is_bridged); + if (!app_ns.Link(platform_ns, system_exposed_libraries)) { + *error_msg = app_ns.GetError(); + return nullptr; + } + + auto runtime_ns = NativeLoaderNamespace::GetExportedNamespace(kRuntimeNamespaceName, is_bridged); + // Runtime apex does not exist in host, and under certain build conditions. + if (!runtime_ns.IsNil()) { + if (!app_ns.Link(runtime_ns, runtime_public_libraries())) { + *error_msg = app_ns.GetError(); + return nullptr; + } + } + + // Give access to VNDK-SP libraries from the 'vndk' namespace. + if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) { + auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged); + if (!vndk_ns.IsNil() && !app_ns.Link(vndk_ns, vndksp_libraries())) { + *error_msg = app_ns.GetError(); + return nullptr; + } + } + + // Note that when vendor_ns is not configured, vendor_ns.IsNil() will be true + // and it will result in linking to the default namespace which is expected + // behavior in this case. + if (!vendor_public_libraries().empty()) { + auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged); + if (!app_ns.Link(vendor_ns, vendor_public_libraries())) { + *error_msg = dlerror(); + return nullptr; + } + } + + namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns)); return &(namespaces_.back().second); } diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index eeee077df..d6304a916 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -220,25 +220,12 @@ void NativeLoaderFreeErrorMessage(char* msg) { #if defined(__ANDROID__) void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge, char** error_msg) { - if (ns->is_android_namespace()) { - android_dlextinfo extinfo; - extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; - extinfo.library_namespace = ns->get_android_ns(); - - void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo); - if (handle == nullptr) { - *error_msg = strdup(dlerror()); - } - *needs_native_bridge = false; - return handle; - } else { - void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns()); - if (handle == nullptr) { - *error_msg = strdup(NativeBridgeGetError()); - } - *needs_native_bridge = true; - return handle; + void* handle = ns->Load(path); + if (handle == nullptr) { + *error_msg = ns->GetError(); } + *needs_native_bridge = ns->IsBridged(); + return handle; } // native_bridge_namespaces are not supported for callers of this function. @@ -247,10 +234,9 @@ void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path, android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { std::lock_guard guard(g_namespaces_mutex); NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader); - if (ns != nullptr) { - return ns->is_android_namespace() ? ns->get_android_ns() : nullptr; + if (ns != nullptr && !ns->IsBridged()) { + return ns->ToRawAndroidNamespace(); } - return nullptr; } diff --git a/libnativeloader/native_loader_namespace.cpp b/libnativeloader/native_loader_namespace.cpp new file mode 100644 index 000000000..e0d4697ca --- /dev/null +++ b/libnativeloader/native_loader_namespace.cpp @@ -0,0 +1,128 @@ +/* + * 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 "android-base/strings.h" +#include "log/log.h" +#include "nativebridge/native_bridge.h" +#include "nativeloader/dlext_namespaces.h" + +namespace android { + +namespace { + +constexpr const char* kDefaultNamespaceName = "default"; +constexpr const char* kPlatformNamespaceName = "platform"; + +} // namespace + +NativeLoaderNamespace NativeLoaderNamespace::GetExportedNamespace(const std::string& name, + bool is_bridged) { + if (!is_bridged) { + return NativeLoaderNamespace(name, android_get_exported_namespace(name.c_str())); + } else { + return NativeLoaderNamespace(name, NativeBridgeGetExportedNamespace(name.c_str())); + } +} + +char* NativeLoaderNamespace::GetError() const { + if (!IsBridged()) { + return strdup(dlerror()); + } else { + return strdup(NativeBridgeGetError()); + } +} + +// The platform namespace is called "default" for binaries in /system and +// "platform" for those in the Runtime APEX. Try "platform" first since +// "default" always exists. +NativeLoaderNamespace NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) { + NativeLoaderNamespace ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged); + if (ns.IsNil()) { + ns = GetExportedNamespace(kDefaultNamespaceName, is_bridged); + } + return ns; +} + +NativeLoaderNamespace 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 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 platform namespace if no parent is set. + const NativeLoaderNamespace& effective_parent = + parent != nullptr ? *parent : GetPlatformNamespace(is_bridged); + + uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED; + 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()); + 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()); + return NativeLoaderNamespace(name, raw); + } +} + +bool 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()) { + return android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(), + shared_libs.c_str()); + } else { + return NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(), + target.ToRawNativeBridgeNamespace(), shared_libs.c_str()); + } +} + +void* NativeLoaderNamespace::Load(const std::string& lib_name) const { + if (!IsBridged()) { + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; + extinfo.library_namespace = this->ToRawAndroidNamespace(); + return android_dlopen_ext(lib_name.c_str(), RTLD_NOW, &extinfo); + } else { + return NativeBridgeLoadLibraryExt(lib_name.c_str(), RTLD_NOW, + this->ToRawNativeBridgeNamespace()); + } +} + +} // namespace android diff --git a/libnativeloader/native_loader_namespace.h b/libnativeloader/native_loader_namespace.h index b983a2ddb..26c62cf09 100644 --- a/libnativeloader/native_loader_namespace.h +++ b/libnativeloader/native_loader_namespace.h @@ -16,13 +16,14 @@ #pragma once #if defined(__ANDROID__) -#include +#include +#include +#include #include "android-base/logging.h" #include "android/dlext.h" #include "log/log.h" #include "nativebridge/native_bridge.h" -#include "utils.h" namespace android { @@ -31,34 +32,40 @@ namespace android { // x86). Instances of this class are managed by LibraryNamespaces object. struct NativeLoaderNamespace { public: - NativeLoaderNamespace() : android_ns_(nullptr), native_bridge_ns_(nullptr) {} - - explicit NativeLoaderNamespace(android_namespace_t* ns) - : android_ns_(ns), native_bridge_ns_(nullptr) {} - - explicit NativeLoaderNamespace(native_bridge_namespace_t* ns) - : android_ns_(nullptr), native_bridge_ns_(ns) {} + // TODO(return with errors) + static 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); NativeLoaderNamespace(NativeLoaderNamespace&&) = default; NativeLoaderNamespace(const NativeLoaderNamespace&) = default; NativeLoaderNamespace& operator=(const NativeLoaderNamespace&) = default; - android_namespace_t* get_android_ns() const { - CHECK(native_bridge_ns_ == nullptr); - return android_ns_; + android_namespace_t* ToRawAndroidNamespace() const { return std::get<0>(raw_); } + native_bridge_namespace_t* ToRawNativeBridgeNamespace() const { return std::get<1>(raw_); } + + std::string name() const { return name_; } + bool IsBridged() const { return raw_.index() == 1; } + bool IsNil() const { + return IsBridged() ? std::get<1>(raw_) == nullptr : std::get<0>(raw_) == nullptr; } - native_bridge_namespace_t* get_native_bridge_ns() const { - CHECK(android_ns_ == nullptr); - return native_bridge_ns_; - } + bool Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const; + void* Load(const std::string& lib_name) const; + char* GetError() const; - bool is_android_namespace() const { return native_bridge_ns_ == nullptr; } + static NativeLoaderNamespace GetExportedNamespace(const std::string& name, bool is_bridged); + static NativeLoaderNamespace GetPlatformNamespace(bool is_bridged); private: - // Only one of them can be not null - android_namespace_t* android_ns_; - native_bridge_namespace_t* native_bridge_ns_; + explicit NativeLoaderNamespace(const std::string& name, android_namespace_t* ns) + : name_(name), raw_(ns) {} + explicit NativeLoaderNamespace(const std::string& name, native_bridge_namespace_t* ns) + : name_(name), raw_(ns) {} + + std::string name_; + std::variant raw_; }; } // namespace android