diff options
| author | 2018-12-13 20:27:33 +0000 | |
|---|---|---|
| committer | 2018-12-13 20:27:33 +0000 | |
| commit | eb922e64f10c19366b4e6844272d112efdfca2b5 (patch) | |
| tree | ebbca0b9059f8eea3ac5fbdcf1138fa54cbfd1b5 | |
| parent | 7c73eca44f2ca7e732b94dca668c40662a50b2f5 (diff) | |
| parent | 769b2e75e1a6e8ee48eba1daad19e99564803637 (diff) | |
Merge "Add facility to limit associations that are allowed between apps."
7 files changed, 647 insertions, 314 deletions
diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java index 3842f6659704..4da339165655 100644 --- a/core/java/com/android/internal/app/procstats/AssociationState.java +++ b/core/java/com/android/internal/app/procstats/AssociationState.java @@ -445,8 +445,18 @@ public final class AssociationState { } } + public boolean hasProcess(String procName) { + final int NSRC = mSources.size(); + for (int isrc = 0; isrc < NSRC; isrc++) { + if (mSources.keyAt(isrc).mProcess.equals(procName)) { + return true; + } + } + return false; + } + public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, - long now, long totalTime, boolean dumpDetails, boolean dumpAll) { + long now, long totalTime, String reqPackage, boolean dumpDetails, boolean dumpAll) { if (dumpAll) { pw.print(prefix); pw.print("mNumActive="); @@ -456,6 +466,9 @@ public final class AssociationState { for (int isrc = 0; isrc < NSRC; isrc++) { final SourceKey key = mSources.keyAt(isrc); final SourceState src = mSources.valueAt(isrc); + if (reqPackage != null && !reqPackage.equals(key.mProcess)) { + continue; + } pw.print(prefixInner); pw.print("<- "); pw.print(key.mProcess); diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java index 54aa533b54d2..9ee583a97b8d 100644 --- a/core/java/com/android/internal/app/procstats/ProcessStats.java +++ b/core/java/com/android/internal/app/procstats/ProcessStats.java @@ -1475,6 +1475,7 @@ public final class ProcessStats implements Parcelable { final int NSRVS = pkgState.mServices.size(); final int NASCS = pkgState.mAssociations.size(); final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName); + boolean onlyAssociations = false; if (!pkgMatch) { boolean procMatch = false; for (int iproc = 0; iproc < NPROCS; iproc++) { @@ -1485,7 +1486,18 @@ public final class ProcessStats implements Parcelable { } } if (!procMatch) { - continue; + // Check if this app has any associations with the requested + // package, so that if so we print those. + for (int iasc = 0; iasc < NASCS; iasc++) { + AssociationState asc = pkgState.mAssociations.valueAt(iasc); + if (asc.hasProcess(reqPackage)) { + onlyAssociations = true; + break; + } + } + if (!onlyAssociations) { + continue; + } } } if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) { @@ -1503,7 +1515,7 @@ public final class ProcessStats implements Parcelable { pw.print(vers); pw.println(":"); } - if ((section & REPORT_PKG_PROC_STATS) != 0) { + if ((section & REPORT_PKG_PROC_STATS) != 0 && !onlyAssociations) { if (!dumpSummary || dumpAll) { for (int iproc = 0; iproc < NPROCS; iproc++) { ProcessState proc = pkgState.mProcesses.valueAt(iproc); @@ -1550,7 +1562,7 @@ public final class ProcessStats implements Parcelable { now, totalTime); } } - if ((section & REPORT_PKG_SVC_STATS) != 0) { + if ((section & REPORT_PKG_SVC_STATS) != 0 && !onlyAssociations) { for (int isvc = 0; isvc < NSRVS; isvc++) { ServiceState svc = pkgState.mServices.valueAt(isvc); if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) { @@ -1579,7 +1591,9 @@ public final class ProcessStats implements Parcelable { for (int iasc = 0; iasc < NASCS; iasc++) { AssociationState asc = pkgState.mAssociations.valueAt(iasc); if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) { - continue; + if (!onlyAssociations || !asc.hasProcess(reqPackage)) { + continue; + } } if (activeOnly && !asc.isInUse()) { pw.print(" (Not active association: "); @@ -1597,7 +1611,8 @@ public final class ProcessStats implements Parcelable { pw.print(" Process: "); pw.println(asc.getProcessName()); asc.dumpStats(pw, " ", " ", " ", - now, totalTime, dumpDetails, dumpAll); + now, totalTime, onlyAssociations ? reqPackage : null, + dumpDetails, dumpAll); } } } diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 2e674a5892c6..841e5b679f5f 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -67,6 +67,7 @@ public class SystemConfig { private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10; private static final int ALLOW_OEM_PERMISSIONS = 0x20; private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x40; + private static final int ALLOW_ASSOCIATIONS = 0x80; private static final int ALLOW_ALL = ~0; // property for runtime configuration differentiation @@ -195,6 +196,12 @@ public class SystemConfig { final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>(); + // Allowed associations between applications. If there are any entries + // for an app, those are the only associations allowed; otherwise, all associations + // are allowed. Allowing an association from app A to app B means app A can not + // associate with any other apps, but does not limit what apps B can associate with. + final ArrayMap<String, ArraySet<String>> mAllowedAssociations = new ArrayMap<>(); + public static SystemConfig getInstance() { synchronized (SystemConfig.class) { if (sInstance == null) { @@ -320,6 +327,10 @@ public class SystemConfig { return Collections.emptyMap(); } + public ArrayMap<String, ArraySet<String>> getAllowedAssociations() { + return mAllowedAssociations; + } + SystemConfig() { // Read configuration from system readPermissions(Environment.buildPath( @@ -329,8 +340,9 @@ public class SystemConfig { readPermissions(Environment.buildPath( Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL); - // Vendors are only allowed to customze libs, features and privapp permissions - int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS; + // Vendors are only allowed to customize these + int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS + | ALLOW_ASSOCIATIONS; if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) { // For backward compatibility vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); @@ -359,8 +371,8 @@ public class SystemConfig { odmPermissionFlag); } - // Allow OEM to customize features and OEM permissions - int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS; + // Allow OEM to customize these + int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS; readPermissions(Environment.buildPath( Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); readPermissions(Environment.buildPath( @@ -423,6 +435,11 @@ public class SystemConfig { } } + private void logNotAllowedInPartition(String name, File permFile, XmlPullParser parser) { + Slog.w(TAG, "<" + name + "> not allowed in partition of " + + permFile + " at " + parser.getPositionDescription()); + } + private void readPermissionsFromXml(File permFile, int permissionFlag) { FileReader permReader = null; try { @@ -453,14 +470,17 @@ public class SystemConfig { + ": found " + parser.getName() + ", expected 'permissions' or 'config'"); } - boolean allowAll = permissionFlag == ALLOW_ALL; - boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0; - boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0; - boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0; - boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0; - boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0; - boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0; - boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) != 0; + final boolean allowAll = permissionFlag == ALLOW_ALL; + final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0; + final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0; + final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0; + final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0; + final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) + != 0; + final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0; + final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) + != 0; + final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0; while (true) { XmlUtils.nextElement(parser); if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { @@ -468,297 +488,425 @@ public class SystemConfig { } String name = parser.getName(); - if ("group".equals(name) && allowAll) { - String gidStr = parser.getAttributeValue(null, "gid"); - if (gidStr != null) { - int gid = android.os.Process.getGidForName(gidStr); - mGlobalGids = appendInt(mGlobalGids, gid); - } else { - Slog.w(TAG, "<group> without gid in " + permFile + " at " - + parser.getPositionDescription()); - } - + if (name == null) { XmlUtils.skipCurrentTag(parser); continue; - } else if ("permission".equals(name) && allowPermissions) { - String perm = parser.getAttributeValue(null, "name"); - if (perm == null) { - Slog.w(TAG, "<permission> without name in " + permFile + " at " - + parser.getPositionDescription()); + } + switch (name) { + case "group": { + if (allowAll) { + String gidStr = parser.getAttributeValue(null, "gid"); + if (gidStr != null) { + int gid = android.os.Process.getGidForName(gidStr); + mGlobalGids = appendInt(mGlobalGids, gid); + } else { + Slog.w(TAG, "<" + name + "> without gid in " + permFile + " at " + + parser.getPositionDescription()); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } XmlUtils.skipCurrentTag(parser); - continue; - } - perm = perm.intern(); - readPermission(parser, perm); - - } else if ("assign-permission".equals(name) && allowPermissions) { - String perm = parser.getAttributeValue(null, "name"); - if (perm == null) { - Slog.w(TAG, "<assign-permission> without name in " + permFile + " at " - + parser.getPositionDescription()); + } break; + case "permission": { + if (allowPermissions) { + String perm = parser.getAttributeValue(null, "name"); + if (perm == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + perm = perm.intern(); + readPermission(parser, perm); + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; + case "assign-permission": { + if (allowPermissions) { + String perm = parser.getAttributeValue(null, "name"); + if (perm == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + String uidStr = parser.getAttributeValue(null, "uid"); + if (uidStr == null) { + Slog.w(TAG, "<" + name + "> without uid in " + permFile + + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + int uid = Process.getUidForName(uidStr); + if (uid < 0) { + Slog.w(TAG, "<" + name + "> with unknown uid \"" + + uidStr + " in " + permFile + " at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + perm = perm.intern(); + ArraySet<String> perms = mSystemPermissions.get(uid); + if (perms == null) { + perms = new ArraySet<String>(); + mSystemPermissions.put(uid, perms); + } + perms.add(perm); + } else { + logNotAllowedInPartition(name, permFile, parser); + } XmlUtils.skipCurrentTag(parser); - continue; - } - String uidStr = parser.getAttributeValue(null, "uid"); - if (uidStr == null) { - Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at " - + parser.getPositionDescription()); + } break; + case "split-permission": { + if (allowPermissions) { + readSplitPermission(parser, permFile); + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; + case "library": { + if (allowLibs) { + String lname = parser.getAttributeValue(null, "name"); + String lfile = parser.getAttributeValue(null, "file"); + String ldependency = parser.getAttributeValue(null, "dependency"); + if (lname == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + + parser.getPositionDescription()); + } else if (lfile == null) { + Slog.w(TAG, "<" + name + "> without file in " + permFile + " at " + + parser.getPositionDescription()); + } else { + //Log.i(TAG, "Got library " + lname + " in " + lfile); + SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, + ldependency == null ? new String[0] : ldependency.split(":")); + mSharedLibraries.put(lname, entry); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } XmlUtils.skipCurrentTag(parser); - continue; - } - int uid = Process.getUidForName(uidStr); - if (uid < 0) { - Slog.w(TAG, "<assign-permission> with unknown uid \"" - + uidStr + " in " + permFile + " at " - + parser.getPositionDescription()); + } break; + case "feature": { + if (allowFeatures) { + String fname = parser.getAttributeValue(null, "name"); + int fversion = XmlUtils.readIntAttribute(parser, "version", 0); + boolean allowed; + if (!lowRam) { + allowed = true; + } else { + String notLowRam = parser.getAttributeValue(null, "notLowRam"); + allowed = !"true".equals(notLowRam); + } + if (fname == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + + parser.getPositionDescription()); + } else if (allowed) { + addFeature(fname, fversion); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } XmlUtils.skipCurrentTag(parser); - continue; - } - perm = perm.intern(); - ArraySet<String> perms = mSystemPermissions.get(uid); - if (perms == null) { - perms = new ArraySet<String>(); - mSystemPermissions.put(uid, perms); - } - perms.add(perm); - XmlUtils.skipCurrentTag(parser); - - } else if ("split-permission".equals(name) && allowPermissions) { - readSplitPermission(parser, permFile); - } else if ("library".equals(name) && allowLibs) { - String lname = parser.getAttributeValue(null, "name"); - String lfile = parser.getAttributeValue(null, "file"); - String ldependency = parser.getAttributeValue(null, "dependency"); - if (lname == null) { - Slog.w(TAG, "<library> without name in " + permFile + " at " - + parser.getPositionDescription()); - } else if (lfile == null) { - Slog.w(TAG, "<library> without file in " + permFile + " at " - + parser.getPositionDescription()); - } else { - //Log.i(TAG, "Got library " + lname + " in " + lfile); - SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, - ldependency == null ? new String[0] : ldependency.split(":")); - mSharedLibraries.put(lname, entry); - } - XmlUtils.skipCurrentTag(parser); - continue; - } else if ("feature".equals(name) && allowFeatures) { - String fname = parser.getAttributeValue(null, "name"); - int fversion = XmlUtils.readIntAttribute(parser, "version", 0); - boolean allowed; - if (!lowRam) { - allowed = true; - } else { - String notLowRam = parser.getAttributeValue(null, "notLowRam"); - allowed = !"true".equals(notLowRam); - } - if (fname == null) { - Slog.w(TAG, "<feature> without name in " + permFile + " at " - + parser.getPositionDescription()); - } else if (allowed) { - addFeature(fname, fversion); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("unavailable-feature".equals(name) && allowFeatures) { - String fname = parser.getAttributeValue(null, "name"); - if (fname == null) { - Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at " - + parser.getPositionDescription()); - } else { - mUnavailableFeatures.add(fname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<allow-in-power-save-except-idle> without package in " - + permFile + " at " + parser.getPositionDescription()); - } else { - mAllowInPowerSaveExceptIdle.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-in-power-save".equals(name) && allowAll) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at " - + parser.getPositionDescription()); - } else { - mAllowInPowerSave.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-in-data-usage-save".equals(name) && allowAll) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mAllowInDataUsageSave.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-unthrottled-location".equals(name) && allowAll) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<allow-unthrottled-location> without package in " - + permFile + " at " + parser.getPositionDescription()); - } else { - mAllowUnthrottledLocation.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-implicit-broadcast".equals(name) && allowAll) { - String action = parser.getAttributeValue(null, "action"); - if (action == null) { - Slog.w(TAG, "<allow-implicit-broadcast> without action in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mAllowImplicitBroadcasts.add(action); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("app-link".equals(name) && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<app-link> without package in " + permFile + " at " - + parser.getPositionDescription()); - } else { - mLinkedApps.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mSystemUserWhitelistedApps.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mSystemUserBlacklistedApps.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - String clsname = parser.getAttributeValue(null, "class"); - if (pkgname == null) { - Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile - + " at " + parser.getPositionDescription()); - } else if (clsname == null) { - Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mDefaultVrComponents.add(new ComponentName(pkgname, clsname)); - } - XmlUtils.skipCurrentTag(parser); - } else if ("backup-transport-whitelisted-service".equals(name) && allowFeatures) { - String serviceName = parser.getAttributeValue(null, "service"); - if (serviceName == null) { - Slog.w(TAG, "<backup-transport-whitelisted-service> without service in " - + permFile + " at " + parser.getPositionDescription()); - } else { - ComponentName cn = ComponentName.unflattenFromString(serviceName); - if (cn == null) { - Slog.w(TAG, - "<backup-transport-whitelisted-service> with invalid service name " - + serviceName + " in "+ permFile - + " at " + parser.getPositionDescription()); + } break; + case "unavailable-feature": { + if (allowFeatures) { + String fname = parser.getAttributeValue(null, "name"); + if (fname == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mUnavailableFeatures.add(fname); + } } else { - mBackupTransportWhitelist.add(cn); + logNotAllowedInPartition(name, permFile, parser); } - } - XmlUtils.skipCurrentTag(parser); - } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name) - && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage"); - if (pkgname == null || carrierPkgname == null) { - Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app" - + " without package or carrierAppPackage in " + permFile + " at " - + parser.getPositionDescription()); - } else { - List<String> associatedPkgs = - mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get( - carrierPkgname); - if (associatedPkgs == null) { - associatedPkgs = new ArrayList<>(); - mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put( - carrierPkgname, associatedPkgs); + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-in-power-save-except-idle": { + if (allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowInPowerSaveExceptIdle.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); } - associatedPkgs.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("disabled-until-used-preinstalled-carrier-app".equals(name) - && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, - "<disabled-until-used-preinstalled-carrier-app> without " - + "package in " + permFile + " at " - + parser.getPositionDescription()); - } else { - mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) { - // privapp permissions from system, vendor, product and product_services - // partitions are stored separately. This is to prevent xml files in the vendor - // partition from granting permissions to priv apps in the system partition and - // vice versa. - boolean vendor = permFile.toPath().startsWith( - Environment.getVendorDirectory().toPath() + "/") - || permFile.toPath().startsWith( - Environment.getOdmDirectory().toPath() + "/"); - boolean product = permFile.toPath().startsWith( - Environment.getProductDirectory().toPath() + "/"); - boolean productServices = permFile.toPath().startsWith( - Environment.getProductServicesDirectory().toPath() + "/"); - if (vendor) { - readPrivAppPermissions(parser, mVendorPrivAppPermissions, - mVendorPrivAppDenyPermissions); - } else if (product) { - readPrivAppPermissions(parser, mProductPrivAppPermissions, - mProductPrivAppDenyPermissions); - } else if (productServices) { - readPrivAppPermissions(parser, mProductServicesPrivAppPermissions, - mProductServicesPrivAppDenyPermissions); - } else { - readPrivAppPermissions(parser, mPrivAppPermissions, - mPrivAppDenyPermissions); - } - } else if ("oem-permissions".equals(name) && allowOemPermissions) { - readOemPermissions(parser); - } else if ("hidden-api-whitelisted-app".equals(name) && allowApiWhitelisting) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<hidden-api-whitelisted-app> without package in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mHiddenApiPackageWhitelist.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else { - Slog.w(TAG, "Tag " + name + " is unknown or not allowed in " - + permFile.getParent()); - XmlUtils.skipCurrentTag(parser); - continue; + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-in-power-save": { + if (allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowInPowerSave.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-in-data-usage-save": { + if (allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowInDataUsageSave.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-unthrottled-location": { + if (allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowUnthrottledLocation.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-implicit-broadcast": { + if (allowAll) { + String action = parser.getAttributeValue(null, "action"); + if (action == null) { + Slog.w(TAG, "<" + name + "> without action in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowImplicitBroadcasts.add(action); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "app-link": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mLinkedApps.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "system-user-whitelisted-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mSystemUserWhitelistedApps.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "system-user-blacklisted-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mSystemUserBlacklistedApps.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "default-enabled-vr-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + String clsname = parser.getAttributeValue(null, "class"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else if (clsname == null) { + Slog.w(TAG, "<" + name + "> without class in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mDefaultVrComponents.add(new ComponentName(pkgname, clsname)); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "backup-transport-whitelisted-service": { + if (allowFeatures) { + String serviceName = parser.getAttributeValue(null, "service"); + if (serviceName == null) { + Slog.w(TAG, "<" + name + "> without service in " + + permFile + " at " + parser.getPositionDescription()); + } else { + ComponentName cn = ComponentName.unflattenFromString(serviceName); + if (cn == null) { + Slog.w(TAG, "<" + name + "> with invalid service name " + + serviceName + " in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mBackupTransportWhitelist.add(cn); + } + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "disabled-until-used-preinstalled-carrier-associated-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + String carrierPkgname = parser.getAttributeValue(null, + "carrierAppPackage"); + if (pkgname == null || carrierPkgname == null) { + Slog.w(TAG, "<" + name + + "> without package or carrierAppPackage in " + permFile + + " at " + parser.getPositionDescription()); + } else { + List<String> associatedPkgs = + mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get( + carrierPkgname); + if (associatedPkgs == null) { + associatedPkgs = new ArrayList<>(); + mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put( + carrierPkgname, associatedPkgs); + } + associatedPkgs.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "disabled-until-used-preinstalled-carrier-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, + "<" + name + "> without " + + "package in " + permFile + " at " + + parser.getPositionDescription()); + } else { + mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "privapp-permissions": { + if (allowPrivappPermissions) { + // privapp permissions from system, vendor, product and product_services + // partitions are stored separately. This is to prevent xml files in + // the vendor partition from granting permissions to priv apps in the + // system partition and vice versa. + boolean vendor = permFile.toPath().startsWith( + Environment.getVendorDirectory().toPath() + "/") + || permFile.toPath().startsWith( + Environment.getOdmDirectory().toPath() + "/"); + boolean product = permFile.toPath().startsWith( + Environment.getProductDirectory().toPath() + "/"); + boolean productServices = permFile.toPath().startsWith( + Environment.getProductServicesDirectory().toPath() + "/"); + if (vendor) { + readPrivAppPermissions(parser, mVendorPrivAppPermissions, + mVendorPrivAppDenyPermissions); + } else if (product) { + readPrivAppPermissions(parser, mProductPrivAppPermissions, + mProductPrivAppDenyPermissions); + } else if (productServices) { + readPrivAppPermissions(parser, mProductServicesPrivAppPermissions, + mProductServicesPrivAppDenyPermissions); + } else { + readPrivAppPermissions(parser, mPrivAppPermissions, + mPrivAppDenyPermissions); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; + case "oem-permissions": { + if (allowOemPermissions) { + readOemPermissions(parser); + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; + case "hidden-api-whitelisted-app": { + if (allowApiWhitelisting) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mHiddenApiPackageWhitelist.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-association": { + if (allowAssociations) { + String target = parser.getAttributeValue(null, "target"); + if (target == null) { + Slog.w(TAG, "<" + name + "> without target in " + permFile + + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + String allowed = parser.getAttributeValue(null, "allowed"); + if (allowed == null) { + Slog.w(TAG, "<" + name + "> without allowed in " + permFile + + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + target = target.intern(); + allowed = allowed.intern(); + ArraySet<String> associations = mAllowedAssociations.get(target); + if (associations == null) { + associations = new ArraySet<>(); + mAllowedAssociations.put(target, associations); + } + Slog.i(TAG, "Adding association: " + target + " <- " + allowed); + associations.add(allowed); + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + default: { + Slog.w(TAG, "Tag " + name + " is unknown in " + + permFile + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + } break; } } } catch (XmlPullParserException e) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index f7acf7e83200..8751d24bcf67 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -2019,6 +2019,13 @@ public final class ActiveServices { ComponentName className = new ComponentName( sInfo.applicationInfo.packageName, sInfo.name); ComponentName name = comp != null ? comp : className; + if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, + name.getPackageName(), sInfo.applicationInfo.uid)) { + String msg = "association not allowed between packages " + + callingPackage + " and " + r.packageName; + Slog.w(TAG, "Service lookup failed: " + msg); + return new ServiceLookupResult(null, msg); + } if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) { if (isBindExternal) { if (!sInfo.exported) { @@ -2099,6 +2106,17 @@ public final class ActiveServices { } } if (r != null) { + if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName, + r.appInfo.uid)) { + String msg = "association not allowed between packages " + + callingPackage + " and " + r.packageName; + Slog.w(TAG, "Service lookup failed: " + msg); + return new ServiceLookupResult(null, msg); + } + if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid, + resolvedType, r.appInfo)) { + return new ServiceLookupResult(null, "blocked by firewall"); + } if (mAm.checkComponentPermission(r.permission, callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) { if (!r.exported) { @@ -2125,11 +2143,6 @@ public final class ActiveServices { return null; } } - - if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid, - resolvedType, r.appInfo)) { - return null; - } return new ServiceLookupResult(r, null); } return null; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8ce37a50557b..6700a530edc0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -658,6 +658,12 @@ public class ActivityManagerService extends IActivityManager.Stub ArraySet<String> mBackgroundLaunchBroadcasts; /** + * When an app has restrictions on the other apps that can have associations with it, + * it appears here with a set of the allowed apps. + */ + ArrayMap<String, ArraySet<String>> mAllowedAssociations; + + /** * All of the processes we currently have running organized by pid. * The keys are the pid running the application. * @@ -2396,6 +2402,34 @@ public class ActivityManagerService extends IActivityManager.Stub return mBackgroundLaunchBroadcasts; } + boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) { + if (mAllowedAssociations == null) { + mAllowedAssociations = SystemConfig.getInstance().getAllowedAssociations(); + } + // Interactions with the system uid are always allowed, since that is the core system + // that everyone needs to be able to interact with. + if (UserHandle.getAppId(uid1) == SYSTEM_UID) { + return true; + } + if (UserHandle.getAppId(uid2) == SYSTEM_UID) { + return true; + } + // We won't allow this association if either pkg1 or pkg2 has a limit on the + // associations that are allowed with it, and the other package is not explicitly + // specified as one of those associations. + ArraySet<String> pkgs = mAllowedAssociations.get(pkg1); + if (pkgs != null) { + if (!pkgs.contains(pkg2)) { + return false; + } + } + pkgs = mAllowedAssociations.get(pkg2); + if (pkgs != null) { + return pkgs.contains(pkg1); + } + return true; + } + @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { @@ -6264,6 +6298,21 @@ public class ActivityManagerService extends IActivityManager.Stub return state != 'Z' && state != 'X' && state != 'x' && state != 'K'; } + private String checkContentProviderAssociation(ProcessRecord callingApp, int callingUid, + ProviderInfo cpi) { + if (callingApp == null) { + return validateAssociationAllowedLocked(cpi.packageName, cpi.applicationInfo.uid, + null, callingUid) ? null : "<null>"; + } + for (int i = callingApp.pkgList.size() - 1; i >= 0; i--) { + if (!validateAssociationAllowedLocked(callingApp.pkgList.keyAt(i), callingApp.uid, + cpi.packageName, cpi.applicationInfo.uid)) { + return cpi.packageName; + } + } + return null; + } + private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, int callingUid, String callingTag, boolean stable, int userId) { @@ -6335,6 +6384,11 @@ public class ActivityManagerService extends IActivityManager.Stub String msg; if (r != null && cpr.canRunHere(r)) { + if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { + throw new SecurityException("Content provider lookup " + + cpr.name.flattenToShortString() + + " failed: association not allowed with package " + msg); + } checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser)) @@ -6364,6 +6418,11 @@ public class ActivityManagerService extends IActivityManager.Stub } catch (RemoteException e) { } + if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { + throw new SecurityException("Content provider lookup " + + cpr.name.flattenToShortString() + + " failed: association not allowed with package " + msg); + } checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser)) @@ -6461,6 +6520,11 @@ public class ActivityManagerService extends IActivityManager.Stub checkTime(startTime, "getContentProviderImpl: got app info for user"); String msg; + if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { + throw new SecurityException("Content provider lookup " + + cpr.name.flattenToShortString() + + " failed: association not allowed with package " + msg); + } checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton)) != null) { @@ -9207,6 +9271,12 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println("-------------------------------------------------------------------------------"); } + dumpAllowedAssociationsLocked(fd, pw, args, opti, dumpAll, dumpPackage); + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + + } mPendingIntentController.dumpPendingIntents(pw, dumpAll, dumpPackage); pw.println(); if (dumpAll) { @@ -9474,6 +9544,14 @@ public class ActivityManagerService extends IActivityManager.Stub System.gc(); pw.println(BinderInternal.nGetBinderProxyCount(Integer.parseInt(uid))); } + } else if ("allowed-associations".equals(cmd)) { + if (opti < args.length) { + dumpPackage = args[opti]; + opti++; + } + synchronized (this) { + dumpAllowedAssociationsLocked(fd, pw, args, opti, true, dumpPackage); + } } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { if (opti < args.length) { dumpPackage = args[opti]; @@ -10824,6 +10902,44 @@ public class ActivityManagerService extends IActivityManager.Stub proto.end(handlerToken); } + void dumpAllowedAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean dumpAll, String dumpPackage) { + boolean needSep = false; + boolean printedAnything = false; + + pw.println("ACTIVITY MANAGER ALLOWED ASSOCIATION STATE (dumpsys activity allowed-associations)"); + boolean printed = false; + if (mAllowedAssociations != null) { + for (int i = 0; i < mAllowedAssociations.size(); i++) { + final String pkg = mAllowedAssociations.keyAt(i); + final ArraySet<String> asc = mAllowedAssociations.valueAt(i); + boolean printedHeader = false; + for (int j = 0; j < asc.size(); j++) { + if (dumpPackage == null || pkg.equals(dumpPackage) + || asc.valueAt(j).equals(dumpPackage)) { + if (!printed) { + pw.println(" Allowed associations (by restricted package):"); + printed = true; + needSep = true; + printedAnything = true; + } + if (!printedHeader) { + pw.print(" * "); + pw.print(pkg); + pw.println(":"); + printedHeader = true; + } + pw.print(" Allow: "); + pw.println(asc.valueAt(j)); + } + } + } + } + if (!printed) { + pw.println(" (No association restrictions)"); + } + } + void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage) { boolean needSep = false; diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 67a4d14a6edb..98a82acd79a6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2852,6 +2852,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" prov[iders] [COMP_SPEC ...]: content provider state"); pw.println(" provider [COMP_SPEC]: provider client-side state"); pw.println(" s[ervices] [COMP_SPEC ...]: service state"); + pw.println(" allowed-associations: current package association restrictions"); pw.println(" as[sociations]: tracked app associations"); pw.println(" lmk: stats on low memory killer"); pw.println(" lru: raw LRU process list"); diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 3a0899de75c3..c290fbe09864 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -527,6 +527,24 @@ public final class BroadcastQueue { private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered, int index) { boolean skip = false; + if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid, + filter.packageName, filter.owningUid)) { + Slog.w(TAG, "Association not allowed: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ") to " + filter.packageName + " through " + + filter); + skip = true; + } + if (!skip && !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, + r.callingPid, r.resolvedType, filter.receiverList.uid)) { + Slog.w(TAG, "Firewall blocked: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ") to " + filter.packageName + " through " + + filter); + skip = true; + } if (filter.requiredPermission != null) { int perm = mService.checkComponentPermission(filter.requiredPermission, r.callingPid, r.callingUid, -1, true); @@ -619,11 +637,6 @@ public final class BroadcastQueue { skip = true; } - if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, - r.callingPid, r.resolvedType, filter.receiverList.uid)) { - skip = true; - } - if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed || filter.receiverList.app.isCrashing())) { Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r @@ -1082,6 +1095,24 @@ public final class BroadcastQueue { > brOptions.getMaxManifestReceiverApiLevel())) { skip = true; } + if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid, + component.getPackageName(), info.activityInfo.applicationInfo.uid)) { + Slog.w(TAG, "Association not allowed: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ") to " + component.flattenToShortString()); + skip = true; + } + if (!skip) { + skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, + r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); + if (skip) { + Slog.w(TAG, "Firewall blocked: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ") to " + component.flattenToShortString()); + } + } int perm = mService.checkComponentPermission(info.activityInfo.permission, r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid, info.activityInfo.exported); @@ -1170,10 +1201,6 @@ public final class BroadcastQueue { + " (uid " + r.callingUid + ")"); skip = true; } - if (!skip) { - skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, - r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); - } boolean isSingleton = false; try { isSingleton = mService.isSingleton(info.activityInfo.processName, |