Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49062966 authored by Hai Zhang's avatar Hai Zhang Committed by Android (Google) Code Review
Browse files

Merge "Add signature permission allowlist." into main

parents dda09bea 62ee3bce
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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"
}
+45 −4
Original line number Diff line number Diff line
@@ -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)
+74 −0
Original line number Diff line number Diff line
@@ -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<>();
@@ -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;
@@ -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);
    }
}
+73 −7
Original line number Diff line number Diff line
@@ -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
@@ -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 ||
@@ -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(