Loading core/java/android/permission/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -86,3 +86,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" } services/core/java/com/android/server/SystemConfig.java +45 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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) Loading services/core/java/com/android/server/pm/permission/PermissionAllowlist.java +74 −0 Original line number Diff line number Diff line Loading @@ -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<>(); Loading @@ -42,6 +43,19 @@ public final class PermissionAllowlist { private final ArrayMap<String, ArrayMap<String, ArrayMap<String, Boolean>>> 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; Loading Loading @@ -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) { Loading Loading @@ -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); } } services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +73 −7 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -1197,7 +1198,8 @@ class AppIdPermissionPolicy : SchemePolicy() { newState.externalState.packageStates[PLATFORM_PACKAGE_NAME]!! .androidPackage!! .signingDetails return sourceSigningDetails?.hasCommonSignerWithCapability( val hasCommonSigner = sourceSigningDetails?.hasCommonSignerWithCapability( packageSigningDetails, SigningDetails.CertCapabilities.PERMISSION ) == true || Loading @@ -1206,6 +1208,70 @@ class AppIdPermissionPolicy : SchemePolicy() { 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( Loading Loading
core/java/android/permission/flags.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -86,3 +86,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" }
services/core/java/com/android/server/SystemConfig.java +45 −4 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); Loading Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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) Loading
services/core/java/com/android/server/pm/permission/PermissionAllowlist.java +74 −0 Original line number Diff line number Diff line Loading @@ -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<>(); Loading @@ -42,6 +43,19 @@ public final class PermissionAllowlist { private final ArrayMap<String, ArrayMap<String, ArrayMap<String, Boolean>>> 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; Loading Loading @@ -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) { Loading Loading @@ -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); } }
services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +73 −7 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -1197,7 +1198,8 @@ class AppIdPermissionPolicy : SchemePolicy() { newState.externalState.packageStates[PLATFORM_PACKAGE_NAME]!! .androidPackage!! .signingDetails return sourceSigningDetails?.hasCommonSignerWithCapability( val hasCommonSigner = sourceSigningDetails?.hasCommonSignerWithCapability( packageSigningDetails, SigningDetails.CertCapabilities.PERMISSION ) == true || Loading @@ -1206,6 +1208,70 @@ class AppIdPermissionPolicy : SchemePolicy() { 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( Loading