Loading libnativeloader/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ cc_library { android: { srcs: [ "library_namespaces.cpp", "native_loader_namespace.cpp", "public_libraries.cpp", ], shared_libs: [ Loading libnativeloader/library_namespaces.cpp +38 −135 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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. Loading @@ -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", Loading @@ -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(); // 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; } // 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); // ... and link to other namespaces to allow access to some public libraries bool is_bridged = app_ns.IsBridged(); if (!android_link_namespaces(ns, platform_ns, system_exposed_libraries.c_str())) { *error_msg = dlerror(); 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 != nullptr) { if (!android_link_namespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) { *error_msg = dlerror(); if (!runtime_ns.IsNil()) { if (!app_ns.Link(runtime_ns, runtime_public_libraries())) { *error_msg = app_ns.GetError(); 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(); // 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()) { if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries().c_str())) { auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged); if (!app_ns.Link(vendor_ns, vendor_public_libraries())) { *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); } namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns)); namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns)); return &(namespaces_.back().second); } Loading libnativeloader/native_loader.cpp +7 −21 Original line number Diff line number Diff line Loading @@ -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); void* handle = ns->Load(path); if (handle == nullptr) { *error_msg = strdup(dlerror()); *error_msg = ns->GetError(); } *needs_native_bridge = false; *needs_native_bridge = ns->IsBridged(); 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; } } // native_bridge_namespaces are not supported for callers of this function. Loading @@ -247,10 +234,9 @@ void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path, android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { std::lock_guard<std::mutex> 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; } Loading libnativeloader/native_loader_namespace.cpp 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * 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 <dlfcn.h> #include <functional> #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 libnativeloader/native_loader_namespace.h +27 −20 Original line number Diff line number Diff line Loading @@ -16,13 +16,14 @@ #pragma once #if defined(__ANDROID__) #include <dlfcn.h> #include <string> #include <variant> #include <vector> #include "android-base/logging.h" #include "android/dlext.h" #include "log/log.h" #include "nativebridge/native_bridge.h" #include "utils.h" namespace android { Loading @@ -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_); } native_bridge_namespace_t* get_native_bridge_ns() const { CHECK(android_ns_ == nullptr); return native_bridge_ns_; 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; } bool is_android_namespace() const { return native_bridge_ns_ == nullptr; } bool Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const; void* Load(const std::string& lib_name) const; char* GetError() const; 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<android_namespace_t*, native_bridge_namespace_t*> raw_; }; } // namespace android Loading Loading
libnativeloader/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ cc_library { android: { srcs: [ "library_namespaces.cpp", "native_loader_namespace.cpp", "public_libraries.cpp", ], shared_libs: [ Loading
libnativeloader/library_namespaces.cpp +38 −135 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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. Loading @@ -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", Loading @@ -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(); // 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; } // 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); // ... and link to other namespaces to allow access to some public libraries bool is_bridged = app_ns.IsBridged(); if (!android_link_namespaces(ns, platform_ns, system_exposed_libraries.c_str())) { *error_msg = dlerror(); 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 != nullptr) { if (!android_link_namespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) { *error_msg = dlerror(); if (!runtime_ns.IsNil()) { if (!app_ns.Link(runtime_ns, runtime_public_libraries())) { *error_msg = app_ns.GetError(); 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(); // 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()) { if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries().c_str())) { auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged); if (!app_ns.Link(vendor_ns, vendor_public_libraries())) { *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); } namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns)); namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns)); return &(namespaces_.back().second); } Loading
libnativeloader/native_loader.cpp +7 −21 Original line number Diff line number Diff line Loading @@ -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); void* handle = ns->Load(path); if (handle == nullptr) { *error_msg = strdup(dlerror()); *error_msg = ns->GetError(); } *needs_native_bridge = false; *needs_native_bridge = ns->IsBridged(); 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; } } // native_bridge_namespaces are not supported for callers of this function. Loading @@ -247,10 +234,9 @@ void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path, android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) { std::lock_guard<std::mutex> 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; } Loading
libnativeloader/native_loader_namespace.cpp 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * 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 <dlfcn.h> #include <functional> #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
libnativeloader/native_loader_namespace.h +27 −20 Original line number Diff line number Diff line Loading @@ -16,13 +16,14 @@ #pragma once #if defined(__ANDROID__) #include <dlfcn.h> #include <string> #include <variant> #include <vector> #include "android-base/logging.h" #include "android/dlext.h" #include "log/log.h" #include "nativebridge/native_bridge.h" #include "utils.h" namespace android { Loading @@ -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_); } native_bridge_namespace_t* get_native_bridge_ns() const { CHECK(android_ns_ == nullptr); return native_bridge_ns_; 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; } bool is_android_namespace() const { return native_bridge_ns_ == nullptr; } bool Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const; void* Load(const std::string& lib_name) const; char* GetError() const; 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<android_namespace_t*, native_bridge_namespace_t*> raw_; }; } // namespace android Loading