From 14626a7c40471090745b7069310a6c6265671fc9 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Thu, 2 Jul 2020 23:17:58 +0900 Subject: libnativeloader understands uses-native-library tag Previously, libnativeloader provided all the partner-provided public shared libraries to apps unconditionally. Starting from Android S, apps targeting S (or higher) get only the libs that are explicited listed as dependencies using the tag in the app manifest. The libs not listed there are not available to the app even if they are registered as public libraries. The changed behavior affects new (S+) apps. Existing apps are not affected; they still get all the libraries. The implementation is rather straightforward. The library accepts a new parameter soname_list from the framework, which is actually from the tags of the app manifest. The list is used to filter the partner-provided libraries when the target sdk is > 30. Bug: 142191088 Test: atest CtsUsesNativeLibraryTest Merged-In: I52e23dda58fc69f51451c5dbeffd0a77125c9bff (cherry picked from commit e741dfd18dcd15f002bc1db9bd6634322e4eeef8) Change-Id: I52e23dda58fc69f51451c5dbeffd0a77125c9bff --- libnativeloader/library_namespaces.cpp | 62 +++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 5 deletions(-) (limited to 'libnativeloader/library_namespaces.cpp') diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp index 14ba721420..330903d028 100644 --- a/libnativeloader/library_namespaces.cpp +++ b/libnativeloader/library_namespaces.cpp @@ -140,11 +140,42 @@ void LibraryNamespaces::Initialize() { } } +// "ALL" is a magic name that allows all public libraries even when the +// target SDK is > 30. Currently this is used for (Java) shared libraries +// which don't use +// TODO(b/142191088) remove this hack +static constexpr const char LIBRARY_ALL[] = "ALL"; + +// Returns the colon-separated list of library names by filtering uses_libraries from +// public_libraries. The returned names will actually be available to the app. If the app is pre-S +// (<= 30), the filtering is not done; the entire public_libraries are provided. +static const std::string filter_public_libraries( + uint32_t target_sdk_version, const std::vector& uses_libraries, + const std::string& public_libraries) { + // Apps targeting Android 11 or earlier gets all public libraries + if (target_sdk_version <= 30) { + return public_libraries; + } + if (std::find(uses_libraries.begin(), uses_libraries.end(), LIBRARY_ALL) != + uses_libraries.end()) { + return public_libraries; + } + std::vector filtered; + std::vector orig = android::base::Split(public_libraries, ":"); + for (const auto& lib : uses_libraries) { + if (std::find(orig.begin(), orig.end(), lib) != orig.end()) { + filtered.emplace_back(lib); + } + } + return android::base::Join(filtered, ":"); +} + Result LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path_j, jstring java_library_path, - jstring java_permitted_path) { + jstring java_permitted_path, + jstring uses_library_list) { std::string library_path; // empty string by default. std::string dex_path; @@ -158,6 +189,23 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t dex_path = dex_path_chars.c_str(); } + std::vector uses_libraries; + if (uses_library_list != nullptr) { + ScopedUtfChars names(env, uses_library_list); + uses_libraries = android::base::Split(names.c_str(), ":"); + } else { + // uses_library_list could be nullptr when System.loadLibrary is called from a + // custom classloader. In that case, we don't know the list of public + // libraries because we don't know which apk the classloader is for. Only + // choices we can have are 1) allowing all public libs (as before), or 2) + // not allowing all but NDK libs. Here we take #1 because #2 would surprise + // developers unnecessarily. + // TODO(b/142191088) finalize the policy here. We could either 1) allow all + // public libs, 2) disallow any lib, or 3) use the libs that were granted to + // the first (i.e. app main) classloader. + uses_libraries.emplace_back(LIBRARY_ALL); + } + ApkOrigin apk_origin = GetApkOriginFromDexPath(dex_path); // (http://b/27588281) This is a workaround for apps using custom @@ -220,10 +268,12 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s", origin_partition, library_path.c_str()); } else { + auto libs = filter_public_libraries(target_sdk_version, uses_libraries, + extended_public_libraries()); // extended public libraries are NOT available to vendor apks, otherwise it // would be system->vendor violation. - if (!extended_public_libraries().empty()) { - system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries(); + if (!libs.empty()) { + system_exposed_libraries = system_exposed_libraries + ':' + libs; } } @@ -338,12 +388,14 @@ Result LibraryNamespaces::Create(JNIEnv* env, uint32_t t } } - if (!vendor_public_libraries().empty()) { + auto vendor_libs = filter_public_libraries(target_sdk_version, uses_libraries, + vendor_public_libraries()); + if (!vendor_libs.empty()) { auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged); // when vendor_ns is not configured, link to the system namespace auto target_ns = vendor_ns.ok() ? vendor_ns : system_ns; if (target_ns.ok()) { - linked = app_ns->Link(*target_ns, vendor_public_libraries()); + linked = app_ns->Link(*target_ns, vendor_libs); if (!linked.ok()) { return linked.error(); } -- cgit v1.2.3-59-g8ed1b