From cfe38cdb1cc45c8b7dcbe4f39329551f6602b9ce Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 4 Jun 2018 15:05:29 +0900 Subject: [PATCH] Fix: vendor public libraries are accessible via System.loadLibrary This CL fixes the problem that vendor public libraries (libs that are listed in /vendor/etc/public.libraries.txt) are not loadable via System.loadLibrary(). (Note that the libs were accessible via dlopen() though.) The problem was happening because when System.loadLibary() is called, the classloader first checks whether the lib is found and accessible in its own native lib search paths. The native lib search paths basically come from the java.library.path property, which in turn is from namespace.default.search.path in /system/etc/ld.config.txt. When VNDK is enforced starting from P, namespace.default.search.path does not have paths other than /system/lib because otherwise system process can have unlimited access to libs in vendor partition. The linker namespace is dynamically configured by the libnativeloader so that only the public vendor libs are accessible. However, as a side effect of removing /vendor/lib from namespace.default.search.path, the classloader always fails to find any lib under /vendor/lib even if the lib is a public one. In order to solve the problem, while keeping rest of the non-public vendor libs from apps, /vendor/lib (and /odm/lib and /product/lib as well) is added to the classloader AFTER native loader is created for the classloader. Bug: 93333337 Test: m -j Test: System.loadLibrary("adsprpc") is successful in Pixel (because libadsprpc.so is in Pixel's vendor public lib list) Test: atest cts/tests/tests/jni Change-Id: Iac12384548cbdd51234568082d02eeba466c160c --- core/java/android/app/LoadedApk.java | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 9db642bb18a3d..494b5474ad005 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -745,6 +745,44 @@ public final class LoadedApk { } } + // /vendor/lib, /odm/lib and /product/lib are added to the native lib search + // paths of the classloader. Note that this is done AFTER the classloader is + // created by ApplicationLoaders.getDefault().getClassLoader(...). The + // reason is because if we have added the paths when creating the classloader + // above, the paths are also added to the search path of the linker namespace + // 'classloader-namespace', which will allow ALL libs in the paths to apps. + // Since only the libs listed in /etc/public.libraries.txt can be + // available to apps, we shouldn't add the paths then. + // + // However, we need to add the paths to the classloader (Java) though. This + // is because when a native lib is requested via System.loadLibrary(), the + // classloader first tries to find the requested lib in its own native libs + // search paths. If a lib is not found in one of the paths, dlopen() is not + // called at all. This can cause a problem that a vendor public native lib + // is accessible when directly opened via dlopen(), but inaccesible via + // System.loadLibrary(). In order to prevent the problem, we explicitly + // add the paths only to the classloader, and not to the native loader + // (linker namespace). + List extraLibPaths = new ArrayList<>(3); + String abiSuffix = VMRuntime.getRuntime().is64Bit() ? "64" : ""; + if (!defaultSearchPaths.contains("/vendor/lib")) { + extraLibPaths.add("/vendor/lib" + abiSuffix); + } + if (!defaultSearchPaths.contains("/odm/lib")) { + extraLibPaths.add("/odm/lib" + abiSuffix); + } + if (!defaultSearchPaths.contains("/product/lib")) { + extraLibPaths.add("/product/lib" + abiSuffix); + } + if (!extraLibPaths.isEmpty()) { + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); + try { + ApplicationLoaders.getDefault().addNative(mClassLoader, extraLibPaths); + } finally { + StrictMode.setThreadPolicy(oldPolicy); + } + } + if (addedPaths != null && addedPaths.size() > 0) { final String add = TextUtils.join(File.pathSeparator, addedPaths); ApplicationLoaders.getDefault().addPath(mClassLoader, add);