From 899c4295652ba6c954c1dc590f9c288849f9119c Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Mon, 29 Jan 2024 19:57:04 +0000 Subject: Give full access to native libs from Java libs in the same partition (reland 2). For both packages and shared Java libs in system image partitions (system, product, vendor), load native libraries from the same partition by using the linker namespace for that partition ("default" or "system", "product", "sphal", respectively). This is only done for native libraries in the /lib(64) directories when specified by an absolute path (i.e. use java.lang.System.load rather than loadLibrary). Otherwise it's looked up using the classloader namespace for the package, as before. Since only loads with absolute paths are affected, compat issues are unlikely. However to be on the safe side it's only enabled for SDK level 35 (VIC) and later (regardless of targetSdkVersion of the package, because the affected code is in system image partitions). This relands https://r.android.com/2933611 but keeps the vendor and product API domain checks unchanged in the CreateClassLoaderNamespace code paths (cf. b/326631342). Test: atest libnativeloader_e2e_tests \ libnativeloader_test libnativeloader_lazy_test Test: libnativeloader_e2e_tests on S, Sv2, T, and U platforms in CI Test: ImsServiceEntitlementUnitTests Bug: 237577392 Change-Id: I246101c1663d81089d9b4ae9450c28d564a7603a --- libnativeloader/native_loader.cpp | 78 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'libnativeloader/native_loader.cpp') diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index 61925431ef..5b4988ae48 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -32,11 +33,13 @@ #include "android-base/macros.h" #include "android-base/strings.h" #include "android-base/thread_annotations.h" +#include "base/macros.h" #include "nativebridge/native_bridge.h" #include "nativehelper/scoped_utf_chars.h" #include "public_libraries.h" #ifdef ART_TARGET_ANDROID +#include "android-modules-utils/sdk_level.h" #include "library_namespaces.h" #include "log/log.h" #include "nativeloader/dlext_namespaces.h" @@ -51,6 +54,9 @@ namespace { using ::android::base::Result; using ::android::nativeloader::LibraryNamespaces; +const std::regex kPartitionNativeLibPathRegex( + "/(system(_ext)?|(system/)?(vendor|product))/lib(64)?/.*"); + // NATIVELOADER_DEFAULT_NAMESPACE_LIBS is an environment variable that can be // used to list extra libraries (separated by ":") that libnativeloader will // load from the default namespace. The libraries must be listed without paths, @@ -87,6 +93,23 @@ std::optional FindApexNamespace(const char* caller_locati return std::nullopt; } +Result GetNamespaceForApiDomain(nativeloader::ApiDomain api_domain, + bool is_bridged) { + switch (api_domain) { + case nativeloader::API_DOMAIN_VENDOR: + return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kVendorNamespaceName, + is_bridged); + case nativeloader::API_DOMAIN_PRODUCT: + return NativeLoaderNamespace::GetExportedNamespace(nativeloader::kProductNamespaceName, + is_bridged); + case nativeloader::API_DOMAIN_SYSTEM: + return NativeLoaderNamespace::GetSystemNamespace(is_bridged); + default: + LOG_FATAL("Invalid API domain %d", api_domain); + UNREACHABLE(); + } +} + Result CreateNativeloaderDefaultNamespaceLibsLink(NativeLoaderNamespace& ns) REQUIRES(g_namespaces_mutex) { const char* links = getenv("NATIVELOADER_DEFAULT_NAMESPACE_LIBS"); @@ -311,6 +334,61 @@ void* OpenNativeLibrary(JNIEnv* env, return handle; } + // If the caller is in any of the system image partitions and the library is + // in the same partition then load it without regards to public library + // restrictions. This is only done if the library is specified by an absolute + // path, so we don't affect the lookup process for libraries specified by name + // only. + if (caller_location != nullptr && + // Check that the library is in the partition-wide native library + // location. Apps in the partition may have their own native libraries, + // and those should still be loaded with the app's classloader namespace. + std::regex_match(path, kPartitionNativeLibPathRegex) && + // Don't do this if the system image is older than V, to avoid any compat + // issues with apps and shared libs in them. + android::modules::sdklevel::IsAtLeastV()) { + nativeloader::ApiDomain caller_api_domain = nativeloader::GetApiDomainFromPath(caller_location); + if (caller_api_domain != nativeloader::API_DOMAIN_DEFAULT) { + nativeloader::ApiDomain library_api_domain = nativeloader::GetApiDomainFromPath(path); + + if (library_api_domain == caller_api_domain) { + bool is_bridged = false; + if (library_path_j != nullptr) { + ScopedUtfChars library_path_utf_chars(env, library_path_j); + if (library_path_utf_chars[0] != '\0') { + is_bridged = NativeBridgeIsPathSupported(library_path_utf_chars.c_str()); + } + } + + Result ns = GetNamespaceForApiDomain(caller_api_domain, is_bridged); + if (!ns.ok()) { + ALOGD("Failed to find ns for caller %s in API domain %d to load %s (is_bridged=%b): %s", + caller_location, + caller_api_domain, + path, + is_bridged, + ns.error().message().c_str()); + *error_msg = strdup(ns.error().message().c_str()); + return nullptr; + } + + *needs_native_bridge = ns.value().IsBridged(); + Result handle = ns.value().Load(path); + ALOGD("Load %s using ns %s for caller %s in same partition (is_bridged=%b): %s", + path, + ns.value().name().c_str(), + caller_location, + is_bridged, + handle.ok() ? "ok" : handle.error().message().c_str()); + if (!handle.ok()) { + *error_msg = strdup(handle.error().message().c_str()); + return nullptr; + } + return handle.value(); + } + } + } + std::lock_guard guard(g_namespaces_mutex); { -- cgit v1.2.3-59-g8ed1b