Don't include inaccessible data dirs in library paths.
When constructing a classloader for a different app, don't include
it's private data dir in libraryPermittedPath if we don't have access
to it. (Which we often won't, although it depends on target SDK,
whether it has a shared UID, etc.)
This avoids generating SELinux denials at boot and other times,
e.g. when initialising WebView.
Bug: 161356067
Test: Boots, denials not seen, WebView works.
Change-Id: Ib246af979783e80fde3313f8aed6c3b7a886e6b2
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index f9b48e7..ffd02c9 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -802,12 +802,9 @@
makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
- String libraryPermittedPath = mDataDir;
- if (mActivityThread == null) {
- // In a zygote context where mActivityThread is null we can't access the app data dir
- // and including this in libraryPermittedPath would cause SELinux denials.
- libraryPermittedPath = "";
- }
+ // Including an inaccessible dir in libraryPermittedPath would cause SELinux denials
+ // when the loader attempts to canonicalise the path. so we don't.
+ String libraryPermittedPath = canAccessDataDir() ? mDataDir : "";
if (isBundledApp) {
// For bundled apps, add the base directory of the app (e.g.,
@@ -951,6 +948,33 @@
}
}
+ /**
+ * Return whether we can access the package's private data directory in order to be able to
+ * load code from it.
+ */
+ private boolean canAccessDataDir() {
+ // In a zygote context where mActivityThread is null we can't access the app data dir.
+ if (mActivityThread == null) {
+ return false;
+ }
+
+ // A package can access its own data directory (the common case, so short-circuit it).
+ if (Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
+ return true;
+ }
+
+ // Temporarily disable logging of disk reads on the Looper thread as this is necessary -
+ // and the loader will access the directory anyway if we don't check it.
+ StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
+ try {
+ // We are constructing a classloader for a different package. It is likely,
+ // but not certain, that we can't acccess its app data dir - so check.
+ return new File(mDataDir).canExecute();
+ } finally {
+ setThreadPolicy(oldPolicy);
+ }
+ }
+
@UnsupportedAppUsage
public ClassLoader getClassLoader() {
synchronized (this) {