diff options
4 files changed, 200 insertions, 11 deletions
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 60143cc79d2d..ecc0cdade45c 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -78,3 +78,11 @@ flag { description: "This flag is used to enabled the Wallet Role for all users on the device" bug: "283989236" } + +flag { + name: "signature_permission_allowlist_enabled" + is_fixed_read_only: true + namespace: "permissions" + description: "Enable signature permission allowlist" + bug: "308573169" +} diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java index 3483c1a1404a..a493d7a57500 100644 --- a/services/core/java/com/android/server/SystemConfig.java +++ b/services/core/java/com/android/server/SystemConfig.java @@ -95,6 +95,7 @@ public class SystemConfig { private static final int ALLOW_OVERRIDE_APP_RESTRICTIONS = 0x100; private static final int ALLOW_IMPLICIT_BROADCASTS = 0x200; private static final int ALLOW_VENDOR_APEX = 0x400; + private static final int ALLOW_SIGNATURE_PERMISSIONS = 0x800; private static final int ALLOW_ALL = ~0; // property for runtime configuration differentiation @@ -597,7 +598,7 @@ public class SystemConfig { // Vendors are only allowed to customize these int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS - | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX; + | ALLOW_SIGNATURE_PERMISSIONS | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX; if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.O_MR1) { // For backward compatibility vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); @@ -649,9 +650,9 @@ public class SystemConfig { // TODO(b/157203468): ALLOW_HIDDENAPI_WHITELISTING must be removed because we prohibited // the use of hidden APIs from the product partition. int productPermissionFlag = ALLOW_FEATURES | ALLOW_LIBS | ALLOW_PERMISSIONS - | ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_HIDDENAPI_WHITELISTING - | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS - | ALLOW_VENDOR_APEX; + | ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_SIGNATURE_PERMISSIONS + | ALLOW_HIDDENAPI_WHITELISTING | ALLOW_ASSOCIATIONS + | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS | ALLOW_VENDOR_APEX; if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) { // TODO(b/157393157): This must check product interface enforcement instead of // DEVICE_INITIAL_SDK_INT for the devices without product interface enforcement. @@ -772,6 +773,8 @@ public class SystemConfig { final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0; final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0; + final boolean allowSignaturePermissions = (permissionFlag & ALLOW_SIGNATURE_PERMISSIONS) + != 0; final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0; final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) != 0; @@ -1246,6 +1249,38 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); } } break; + case "signature-permissions": { + if (allowSignaturePermissions) { + // signature permissions from system, apex, vendor, product and + // system_ext partitions are stored separately. This is to + // prevent xml files in the vendor partition from granting + // permissions to signature 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 systemExt = permFile.toPath().startsWith( + Environment.getSystemExtDirectory().toPath() + "/"); + if (vendor) { + readSignatureAppPermissions(parser, + mPermissionAllowlist.getVendorSignatureAppAllowlist()); + } else if (product) { + readSignatureAppPermissions(parser, + mPermissionAllowlist.getProductSignatureAppAllowlist()); + } else if (systemExt) { + readSignatureAppPermissions(parser, + mPermissionAllowlist.getSystemExtSignatureAppAllowlist()); + } else { + readSignatureAppPermissions(parser, + mPermissionAllowlist.getSignatureAppAllowlist()); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; case "oem-permissions": { if (allowOemPermissions) { readOemPermissions(parser); @@ -1655,6 +1690,12 @@ public class SystemConfig { readPermissionAllowlist(parser, allowlist, "privapp-permissions"); } + private void readSignatureAppPermissions(@NonNull XmlPullParser parser, + @NonNull ArrayMap<String, ArrayMap<String, Boolean>> allowlist) + throws IOException, XmlPullParserException { + readPermissionAllowlist(parser, allowlist, "signature-permissions"); + } + private void readInstallInUserType(XmlPullParser parser, Map<String, Set<String>> doInstallMap, Map<String, Set<String>> nonInstallMap) diff --git a/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java b/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java index 3efac81d44e3..d138606369b9 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java +++ b/services/core/java/com/android/server/pm/permission/PermissionAllowlist.java @@ -26,6 +26,7 @@ import android.util.ArrayMap; public final class PermissionAllowlist { @NonNull private final ArrayMap<String, ArrayMap<String, Boolean>> mOemAppAllowlist = new ArrayMap<>(); + @NonNull private final ArrayMap<String, ArrayMap<String, Boolean>> mPrivilegedAppAllowlist = new ArrayMap<>(); @@ -43,6 +44,19 @@ public final class PermissionAllowlist { mApexPrivilegedAppAllowlists = new ArrayMap<>(); @NonNull + private final ArrayMap<String, ArrayMap<String, Boolean>> mSignatureAppAllowlist = + new ArrayMap<>(); + @NonNull + private final ArrayMap<String, ArrayMap<String, Boolean>> mVendorSignatureAppAllowlist = + new ArrayMap<>(); + @NonNull + private final ArrayMap<String, ArrayMap<String, Boolean>> mProductSignatureAppAllowlist = + new ArrayMap<>(); + @NonNull + private final ArrayMap<String, ArrayMap<String, Boolean>> mSystemExtSignatureAppAllowlist = + new ArrayMap<>(); + + @NonNull public ArrayMap<String, ArrayMap<String, Boolean>> getOemAppAllowlist() { return mOemAppAllowlist; } @@ -73,6 +87,26 @@ public final class PermissionAllowlist { return mApexPrivilegedAppAllowlists; } + @NonNull + public ArrayMap<String, ArrayMap<String, Boolean>> getSignatureAppAllowlist() { + return mSignatureAppAllowlist; + } + + @NonNull + public ArrayMap<String, ArrayMap<String, Boolean>> getVendorSignatureAppAllowlist() { + return mVendorSignatureAppAllowlist; + } + + @NonNull + public ArrayMap<String, ArrayMap<String, Boolean>> getProductSignatureAppAllowlist() { + return mProductSignatureAppAllowlist; + } + + @NonNull + public ArrayMap<String, ArrayMap<String, Boolean>> getSystemExtSignatureAppAllowlist() { + return mSystemExtSignatureAppAllowlist; + } + @Nullable public Boolean getOemAppAllowlistState(@NonNull String packageName, @NonNull String permissionName) { @@ -137,4 +171,44 @@ public final class PermissionAllowlist { } return permissions.get(permissionName); } + + @Nullable + public Boolean getSignatureAppAllowlistState(@NonNull String packageName, + @NonNull String permissionName) { + ArrayMap<String, Boolean> permissions = mSignatureAppAllowlist.get(packageName); + if (permissions == null) { + return null; + } + return permissions.get(permissionName); + } + + @Nullable + public Boolean getVendorSignatureAppAllowlistState(@NonNull String packageName, + @NonNull String permissionName) { + ArrayMap<String, Boolean> permissions = mVendorSignatureAppAllowlist.get(packageName); + if (permissions == null) { + return null; + } + return permissions.get(permissionName); + } + + @Nullable + public Boolean getProductSignatureAppAllowlistState(@NonNull String packageName, + @NonNull String permissionName) { + ArrayMap<String, Boolean> permissions = mProductSignatureAppAllowlist.get(packageName); + if (permissions == null) { + return null; + } + return permissions.get(permissionName); + } + + @Nullable + public Boolean getSystemExtSignatureAppAllowlistState(@NonNull String packageName, + @NonNull String permissionName) { + ArrayMap<String, Boolean> permissions = mSystemExtSignatureAppAllowlist.get(packageName); + if (permissions == null) { + return null; + } + return permissions.get(permissionName); + } } diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt index 022268df4a63..823c8839c90e 100644 --- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt @@ -22,6 +22,7 @@ import android.content.pm.PermissionGroupInfo import android.content.pm.PermissionInfo import android.content.pm.SigningDetails import android.os.Build +import android.permission.flags.Flags import android.util.Slog import com.android.internal.os.RoSystemProperties import com.android.internal.pm.permission.CompatibilityPermissionInfo @@ -1193,15 +1194,80 @@ class AppIdPermissionPolicy : SchemePolicy() { newState.externalState.packageStates[PLATFORM_PACKAGE_NAME]!! .androidPackage!! .signingDetails - return sourceSigningDetails?.hasCommonSignerWithCapability( - packageSigningDetails, - SigningDetails.CertCapabilities.PERMISSION - ) == true || - packageSigningDetails.hasAncestorOrSelf(platformSigningDetails) || - platformSigningDetails.checkCapability( + val hasCommonSigner = + sourceSigningDetails?.hasCommonSignerWithCapability( packageSigningDetails, SigningDetails.CertCapabilities.PERMISSION - ) + ) == true || + packageSigningDetails.hasAncestorOrSelf(platformSigningDetails) || + platformSigningDetails.checkCapability( + packageSigningDetails, + SigningDetails.CertCapabilities.PERMISSION + ) + if (!Flags.signaturePermissionAllowlistEnabled()) { + return hasCommonSigner; + } + if (!hasCommonSigner) { + return false + } + // A platform signature permission also needs to be allowlisted on non-debuggable builds. + if (permission.packageName == PLATFORM_PACKAGE_NAME) { + val isRequestedByFactoryApp = + if (packageState.isSystem) { + // For updated system applications, a signature permission still needs to be + // allowlisted if it wasn't requested by the original application. + if (packageState.isUpdatedSystemApp) { + val disabledSystemPackage = + newState.externalState.disabledSystemPackageStates[ + packageState.packageName] + ?.androidPackage + disabledSystemPackage != null && + permission.name in disabledSystemPackage.requestedPermissions + } else { + true + } + } else { + false + } + if ( + !(isRequestedByFactoryApp || + getSignaturePermissionAllowlistState(packageState, permission.name) == true) + ) { + Slog.w( + LOG_TAG, + "Signature permission ${permission.name} for package" + + " ${packageState.packageName} (${packageState.path}) not in" + + " signature permission allowlist" + ) + if (!Build.isDebuggable()) { + return false + } + } + } + return true + } + + private fun MutateStateScope.getSignaturePermissionAllowlistState( + packageState: PackageState, + permissionName: String + ): Boolean? { + val permissionAllowlist = newState.externalState.permissionAllowlist + val packageName = packageState.packageName + return when { + packageState.isVendor || packageState.isOdm -> + permissionAllowlist.getVendorSignatureAppAllowlistState(packageName, permissionName) + packageState.isProduct -> + permissionAllowlist.getProductSignatureAppAllowlistState( + packageName, + permissionName + ) + packageState.isSystemExt -> + permissionAllowlist.getSystemExtSignatureAppAllowlistState( + packageName, + permissionName + ) + else -> permissionAllowlist.getSignatureAppAllowlistState(packageName, permissionName) + } } private fun MutateStateScope.checkPrivilegedPermissionAllowlist( |