From f654371d53806f86d647c4fca97240992244986b Mon Sep 17 00:00:00 2001 From: Alan Stokes Date: Tue, 21 Jul 2020 17:38:59 +0100 Subject: [PATCH] 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 --- core/java/android/app/LoadedApk.java | 36 +++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index f9b48e7101483..ffd02c9256066 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -802,12 +802,9 @@ public final class LoadedApk { 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 @@ public final class LoadedApk { } } + /** + * 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) {