Give full access to system libs from other system libs.
In particular this addresses the case when an app without a shared
namespace loads a shared system library that in turn loads a system JNI
library.
Give full access both ways between /system and /system_ext libraries,
and add a shared system_ext library and loading from system_ext to test
that.
Cherry-picked from https://r.android.com/2211602.
Test: atest libnativeloader_e2e_tests
Bug: 237577392
Change-Id: Ief4e24dadbadd26c5602c9e593276fae01bd7038
Merged-In: Ief4e24dadbadd26c5602c9e593276fae01bd7038
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
index 96d4dde..4fbf798 100644
--- a/libnativeloader/library_namespaces.cpp
+++ b/libnativeloader/library_namespaces.cpp
@@ -82,15 +82,18 @@
constexpr const char* kVendorLibPath = "/vendor/" LIB;
constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB;
+constexpr const char* kSystemLibPath = "/system/" LIB ":/system_ext/" LIB;
const std::regex kVendorDexPathRegex("(^|:)/vendor/");
const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
+const std::regex kSystemDexPathRegex("(^|:)/system(_ext)?/"); // MUST be tested last.
-// Define origin of APK if it is from vendor partition or product partition
+// Define origin partition of APK
using ApkOrigin = enum {
APK_ORIGIN_DEFAULT = 0,
APK_ORIGIN_VENDOR = 1,
- APK_ORIGIN_PRODUCT = 2,
+ APK_ORIGIN_PRODUCT = 2, // Includes both /product and /system/product
+ APK_ORIGIN_SYSTEM = 3, // Includes both /system and /system_ext but not /system/product
};
jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
@@ -113,6 +116,9 @@
apk_origin = APK_ORIGIN_PRODUCT;
}
+ if (apk_origin == APK_ORIGIN_DEFAULT && std::regex_search(dex_path, kSystemDexPathRegex)) {
+ apk_origin = APK_ORIGIN_SYSTEM;
+ }
return apk_origin;
}
@@ -234,7 +240,18 @@
const char* apk_origin_msg = "other apk"; // Only for debug logging.
if (!is_shared) {
- if (apk_origin == APK_ORIGIN_VENDOR) {
+ if (apk_origin == APK_ORIGIN_SYSTEM) {
+ // System apps commonly get shared namespaces and hence don't need this.
+ // In practice it's necessary for shared system libraries (i.e. JARs
+ // rather than actual APKs) that are loaded by ordinary apps which don't
+ // get shared namespaces.
+ apk_origin_msg = "system apk";
+
+ // Give access to all libraries in the system and system_ext partitions
+ // (they can freely access each other's private APIs).
+ library_path = library_path + ":" + kSystemLibPath;
+ permitted_path = permitted_path + ":" + kSystemLibPath;
+ } else if (apk_origin == APK_ORIGIN_VENDOR) {
unbundled_app_origin = APK_ORIGIN_VENDOR;
apk_origin_msg = "unbundled vendor apk";
@@ -288,8 +305,7 @@
// they are to other apps, including those in system, system_ext, and
// product partitions. The reason is that when GSI is used, the system
// partition may get replaced, and then vendor apps may fail. It's fine for
- // product (and system_ext) apps, because those partitions aren't mounted in
- // GSI tests.
+ // product apps, because that partition isn't mounted in GSI tests.
auto libs =
filter_public_libraries(target_sdk_version, uses_libraries, extended_public_libraries());
if (!libs.empty()) {
diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp
index b43a02c..1d3a07a 100644
--- a/libnativeloader/test/Android.bp
+++ b/libnativeloader/test/Android.bp
@@ -55,6 +55,13 @@
srcs: ["src/android/test/systemsharedlib/SystemSharedLib.java"],
}
+// Test fixture that represents a shared library in /system_ext/framework.
+java_library {
+ name: "libnativeloader_system_ext_shared_lib",
+ installable: true,
+ srcs: ["src/android/test/systemextsharedlib/SystemExtSharedLib.java"],
+}
+
java_defaults {
name: "loadlibrarytest_app_defaults",
defaults: ["art_module_source_build_java_defaults"],
@@ -63,7 +70,10 @@
"androidx.test.rules",
"loadlibrarytest_test_utils",
],
- libs: ["libnativeloader_system_shared_lib"],
+ libs: [
+ "libnativeloader_system_shared_lib",
+ "libnativeloader_system_ext_shared_lib",
+ ],
}
android_test_helper_app {
@@ -125,6 +135,7 @@
data: [
":library_container_app",
":libnativeloader_system_shared_lib",
+ ":libnativeloader_system_ext_shared_lib",
":loadlibrarytest_system_priv_app",
":loadlibrarytest_system_app",
":loadlibrarytest_system_ext_app",
diff --git a/libnativeloader/test/loadlibrarytest_data_app_manifest.xml b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml
index 9b663e6..2af0af4 100644
--- a/libnativeloader/test/loadlibrarytest_data_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_data_app_manifest.xml
@@ -21,6 +21,7 @@
android:targetPackage="android.test.app.data" />
<application>
<uses-library android:name="android.test.systemsharedlib" />
+ <uses-library android:name="android.test.systemextsharedlib" />
<uses-native-library android:required="false" android:name="libfoo.oem1.so" />
<uses-native-library android:required="false" android:name="libbar.oem1.so" />
<uses-native-library android:required="false" android:name="libfoo.oem2.so" />
diff --git a/libnativeloader/test/loadlibrarytest_product_app_manifest.xml b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml
index c1d997a..614f33f 100644
--- a/libnativeloader/test/loadlibrarytest_product_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_product_app_manifest.xml
@@ -21,6 +21,7 @@
android:targetPackage="android.test.app.product" />
<application>
<uses-library android:name="android.test.systemsharedlib" />
+ <uses-library android:name="android.test.systemextsharedlib" />
<uses-native-library android:required="false" android:name="libfoo.oem1.so" />
<uses-native-library android:required="false" android:name="libbar.oem1.so" />
<uses-native-library android:required="false" android:name="libfoo.oem2.so" />
diff --git a/libnativeloader/test/loadlibrarytest_system_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml
index 5c6af09..5711f65 100644
--- a/libnativeloader/test/loadlibrarytest_system_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_system_app_manifest.xml
@@ -21,6 +21,7 @@
android:targetPackage="android.test.app.system" />
<application>
<uses-library android:name="android.test.systemsharedlib" />
+ <uses-library android:name="android.test.systemextsharedlib" />
<!-- System apps get a shared classloader namespace, so they don't need
uses-native-library entries for anything in /system. -->
<uses-native-library android:required="false" android:name="libfoo.product1.so" />
diff --git a/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml
index 961f9ba..8aa3fa9 100644
--- a/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_system_ext_app_manifest.xml
@@ -21,6 +21,7 @@
android:targetPackage="android.test.app.system_ext" />
<application>
<uses-library android:name="android.test.systemsharedlib" />
+ <uses-library android:name="android.test.systemextsharedlib" />
<!-- System apps get a shared classloader namespace, so they don't need
uses-native-library entries for anything in /system. -->
<uses-native-library android:required="false" android:name="libfoo.product1.so" />
diff --git a/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml
index f4bf3c0..126453c 100644
--- a/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_system_priv_app_manifest.xml
@@ -21,6 +21,7 @@
android:targetPackage="android.test.app.system_priv" />
<application>
<uses-library android:name="android.test.systemsharedlib" />
+ <uses-library android:name="android.test.systemextsharedlib" />
<!-- System apps get a shared classloader namespace, so they don't need
uses-native-library entries for anything in /system. -->
<uses-native-library android:required="false" android:name="libfoo.product1.so" />
diff --git a/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml
index 1a8cbcc..a2a9f64 100644
--- a/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml
+++ b/libnativeloader/test/loadlibrarytest_vendor_app_manifest.xml
@@ -21,6 +21,7 @@
android:targetPackage="android.test.app.vendor" />
<application>
<uses-library android:name="android.test.systemsharedlib" />
+ <uses-library android:name="android.test.systemextsharedlib" />
<uses-native-library android:required="false" android:name="libfoo.oem1.so" />
<uses-native-library android:required="false" android:name="libbar.oem1.so" />
<uses-native-library android:required="false" android:name="libfoo.oem2.so" />
diff --git a/libnativeloader/test/src/android/test/app/DataAppTest.java b/libnativeloader/test/src/android/test/app/DataAppTest.java
index db97e8d..767a7b1 100644
--- a/libnativeloader/test/src/android/test/app/DataAppTest.java
+++ b/libnativeloader/test/src/android/test/app/DataAppTest.java
@@ -17,6 +17,7 @@
package android.test.app;
import android.test.lib.TestUtils;
+import android.test.systemextsharedlib.SystemExtSharedLib;
import android.test.systemsharedlib.SystemSharedLib;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -40,16 +41,24 @@
@Test
public void testLoadPrivateLibraries() {
TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1"));
+ TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1"));
TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1"));
TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1"));
}
@Test
public void testLoadPrivateLibrariesViaSystemSharedLib() {
- // TODO(b/237577392): Fix this use case.
- TestUtils.assertLinkerNamespaceError(() -> SystemSharedLib.loadLibrary("system_private2"));
-
+ SystemSharedLib.loadLibrary("system_private2");
+ SystemSharedLib.loadLibrary("systemext_private2");
TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2"));
TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2"));
}
+
+ @Test
+ public void testLoadPrivateLibrariesViaSystemExtSharedLib() {
+ SystemExtSharedLib.loadLibrary("system_private3");
+ SystemExtSharedLib.loadLibrary("systemext_private3");
+ TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3"));
+ TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3"));
+ }
}
diff --git a/libnativeloader/test/src/android/test/app/ProductAppTest.java b/libnativeloader/test/src/android/test/app/ProductAppTest.java
index a9b8697..1f36798 100644
--- a/libnativeloader/test/src/android/test/app/ProductAppTest.java
+++ b/libnativeloader/test/src/android/test/app/ProductAppTest.java
@@ -17,6 +17,7 @@
package android.test.app;
import android.test.lib.TestUtils;
+import android.test.systemextsharedlib.SystemExtSharedLib;
import android.test.systemsharedlib.SystemSharedLib;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -40,16 +41,24 @@
@Test
public void testLoadPrivateLibraries() {
TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1"));
+ TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1"));
System.loadLibrary("product_private1");
TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1"));
}
@Test
public void testLoadPrivateLibrariesViaSystemSharedLib() {
- // TODO(b/237577392): Fix this use case.
- TestUtils.assertLinkerNamespaceError(() -> SystemSharedLib.loadLibrary("system_private2"));
-
+ SystemSharedLib.loadLibrary("system_private2");
+ SystemSharedLib.loadLibrary("systemext_private2");
TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2"));
TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2"));
}
+
+ @Test
+ public void testLoadPrivateLibrariesViaSystemExtSharedLib() {
+ SystemExtSharedLib.loadLibrary("system_private3");
+ SystemExtSharedLib.loadLibrary("systemext_private3");
+ TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3"));
+ TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3"));
+ }
}
diff --git a/libnativeloader/test/src/android/test/app/SystemAppTest.java b/libnativeloader/test/src/android/test/app/SystemAppTest.java
index 6644478..197a40c 100644
--- a/libnativeloader/test/src/android/test/app/SystemAppTest.java
+++ b/libnativeloader/test/src/android/test/app/SystemAppTest.java
@@ -17,6 +17,7 @@
package android.test.app;
import android.test.lib.TestUtils;
+import android.test.systemextsharedlib.SystemExtSharedLib;
import android.test.systemsharedlib.SystemSharedLib;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -40,6 +41,7 @@
@Test
public void testLoadPrivateLibraries() {
System.loadLibrary("system_private1");
+ System.loadLibrary("systemext_private1");
TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1"));
TestUtils.assertLibraryNotFound(() -> System.loadLibrary("vendor_private1"));
}
@@ -47,7 +49,16 @@
@Test
public void testLoadPrivateLibrariesViaSystemSharedLib() {
SystemSharedLib.loadLibrary("system_private2");
+ SystemSharedLib.loadLibrary("systemext_private2");
TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2"));
TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2"));
}
+
+ @Test
+ public void testLoadPrivateLibrariesViaSystemExtSharedLib() {
+ SystemExtSharedLib.loadLibrary("system_private3");
+ SystemExtSharedLib.loadLibrary("systemext_private3");
+ TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3"));
+ TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3"));
+ }
}
diff --git a/libnativeloader/test/src/android/test/app/VendorAppTest.java b/libnativeloader/test/src/android/test/app/VendorAppTest.java
index 5187ac8..c9ce8db 100644
--- a/libnativeloader/test/src/android/test/app/VendorAppTest.java
+++ b/libnativeloader/test/src/android/test/app/VendorAppTest.java
@@ -17,6 +17,7 @@
package android.test.app;
import android.test.lib.TestUtils;
+import android.test.systemextsharedlib.SystemExtSharedLib;
import android.test.systemsharedlib.SystemSharedLib;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -39,6 +40,7 @@
@Test
public void testLoadPrivateLibraries() {
TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("system_private1"));
+ TestUtils.assertLinkerNamespaceError(() -> System.loadLibrary("systemext_private1"));
TestUtils.assertLibraryNotFound(() -> System.loadLibrary("product_private1"));
// TODO(mast): The vendor app fails to load a private vendor library because it gets
// classified as untrusted_app in SELinux, which doesn't have access to vendor_file. Even an
@@ -49,10 +51,17 @@
@Test
public void testLoadPrivateLibrariesViaSystemSharedLib() {
- // TODO(b/237577392): Fix this use case.
- TestUtils.assertLinkerNamespaceError(() -> SystemSharedLib.loadLibrary("system_private2"));
-
+ SystemSharedLib.loadLibrary("system_private2");
+ SystemSharedLib.loadLibrary("systemext_private2");
TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("product_private2"));
TestUtils.assertLibraryNotFound(() -> SystemSharedLib.loadLibrary("vendor_private2"));
}
+
+ @Test
+ public void testLoadPrivateLibrariesViaSystemExtSharedLib() {
+ SystemExtSharedLib.loadLibrary("system_private3");
+ SystemExtSharedLib.loadLibrary("systemext_private3");
+ TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("product_private3"));
+ TestUtils.assertLibraryNotFound(() -> SystemExtSharedLib.loadLibrary("vendor_private3"));
+ }
}
diff --git a/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
index c908a49..c929037 100644
--- a/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
+++ b/libnativeloader/test/src/android/test/hostside/LibnativeloaderTest.java
@@ -69,7 +69,10 @@
ctx.pushExtendedPublicProductLibs(libApk);
ctx.pushPrivateLibs(libApk);
}
- ctx.pushSystemSharedLib();
+ ctx.pushSystemSharedLib("/system/framework", "android.test.systemsharedlib",
+ "libnativeloader_system_shared_lib.jar");
+ ctx.pushSystemSharedLib("/system_ext/framework", "android.test.systemextsharedlib",
+ "libnativeloader_system_ext_shared_lib.jar");
// "Install" apps in various partitions through plain adb push followed by a soft reboot. We
// need them in these locations to test library loading restrictions, so for all except
@@ -230,17 +233,18 @@
void pushPrivateLibs(ZipFile libApk) throws Exception {
// Push the libraries once for each test. Since we cannot unload them, we need a fresh
// never-before-loaded library in each loadLibrary call.
- for (int i = 1; i <= 2; ++i) {
+ for (int i = 1; i <= 3; ++i) {
pushNativeTestLib(libApk, "/system/${LIB}/libsystem_private" + i + ".so");
+ pushNativeTestLib(libApk, "/system_ext/${LIB}/libsystemext_private" + i + ".so");
pushNativeTestLib(libApk, "/product/${LIB}/libproduct_private" + i + ".so");
pushNativeTestLib(libApk, "/vendor/${LIB}/libvendor_private" + i + ".so");
}
}
- void pushSystemSharedLib() throws Exception {
- String packageName = "android.test.systemsharedlib";
- String path = "/system/framework/" + packageName + ".jar";
- pushFile("libnativeloader_system_shared_lib.jar", path);
+ void pushSystemSharedLib(String packageDir, String packageName, String buildJarName)
+ throws Exception {
+ String path = packageDir + "/" + packageName + ".jar";
+ pushFile(buildJarName, path);
pushString("<permissions>\n"
+ "<library name=\"" + packageName + "\" file=\"" + path + "\" />\n"
+ "</permissions>\n",
diff --git a/libnativeloader/test/src/android/test/systemextsharedlib/SystemExtSharedLib.java b/libnativeloader/test/src/android/test/systemextsharedlib/SystemExtSharedLib.java
new file mode 100644
index 0000000..1240e12
--- /dev/null
+++ b/libnativeloader/test/src/android/test/systemextsharedlib/SystemExtSharedLib.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+package android.test.systemextsharedlib;
+
+public final class SystemExtSharedLib {
+ public static void loadLibrary(String name) { System.loadLibrary(name); }
+}