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

Commit 324b6929 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Make SOFT_RESTRICTED reflect actual restriction state" into main

parents d7ccf158 f23a8b18
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_NONE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
@@ -148,7 +147,7 @@ public abstract class SoftRestrictedPermissionPolicy {
                            pkg.hasPreserveLegacyExternalStorage();
                    targetSDK = getMinimumTargetSDK(context, appInfo, user);

                    shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
                    shouldApplyRestriction = !isWhiteListed;
                    isForcedScopedStorage = sForcedScopedStorageAppWhitelist
                            .contains(appInfo.packageName);
                } else {
+67 −17
Original line number Diff line number Diff line
@@ -227,23 +227,57 @@ class AppIdPermissionPolicy : SchemePolicy() {
            if (isRequestedBySystemPackage) {
                return@forEach
            }
            updatePermissionExemptFlags(
                appId,
                userId,
                permission,
                PermissionFlags.UPGRADE_EXEMPT,
                0
            )
        }
    }

    fun MutateStateScope.updatePermissionExemptFlags(
        appId: Int,
        userId: Int,
        permission: Permission,
        exemptFlagMask: Int,
        exemptFlagValues: Int
    ) {
        val permissionName = permission.name
        val oldFlags = getPermissionFlags(appId, userId, permissionName)
            var newFlags = oldFlags andInv PermissionFlags.UPGRADE_EXEMPT
        var newFlags = (oldFlags andInv exemptFlagMask) or (exemptFlagValues and exemptFlagMask)
        if (oldFlags == newFlags) {
            return
        }
        val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)
            newFlags =
        if (permission.isHardRestricted && !isExempt) {
                    newFlags or PermissionFlags.RESTRICTION_REVOKED
            newFlags = newFlags or PermissionFlags.RESTRICTION_REVOKED
            // If the permission was policy fixed as granted but it is no longer on any of the
            // allowlists we need to clear the policy fixed flag as allowlisting trumps policy i.e.
            // policy cannot grant a non grantable permission.
            if (PermissionFlags.isPermissionGranted(oldFlags)) {
                newFlags = newFlags andInv PermissionFlags.POLICY_FIXED
            }
        } else {
                    newFlags andInv PermissionFlags.RESTRICTION_REVOKED
            newFlags = newFlags andInv PermissionFlags.RESTRICTION_REVOKED
        }
        newFlags =
                if (permission.isSoftRestricted && !isExempt) {
            if (
                permission.isSoftRestricted && !isExempt &&
                    !anyPackageInAppId(appId) {
                        permissionName in it.androidPackage!!.requestedPermissions &&
                            isSoftRestrictedPermissionExemptForPackage(it, permissionName)
                    }
            ) {
                newFlags or PermissionFlags.SOFT_RESTRICTED
            } else {
                newFlags andInv PermissionFlags.SOFT_RESTRICTED
            }
            setPermissionFlags(appId, userId, permissionName, newFlags)
        if (oldFlags == newFlags) {
            return
        }
        setPermissionFlags(appId, userId, permissionName, newFlags)
    }

    override fun MutateStateScope.onPackageUninstalled(
@@ -1118,7 +1152,12 @@ class AppIdPermissionPolicy : SchemePolicy() {
                    newFlags andInv PermissionFlags.RESTRICTION_REVOKED
                }
            newFlags =
                if (permission.isSoftRestricted && !isExempt) {
                if (
                    permission.isSoftRestricted && !isExempt &&
                        !requestingPackageStates.anyIndexed { _, it ->
                            isSoftRestrictedPermissionExemptForPackage(it, permissionName)
                        }
                ) {
                    newFlags or PermissionFlags.SOFT_RESTRICTED
                } else {
                    newFlags andInv PermissionFlags.SOFT_RESTRICTED
@@ -1398,6 +1437,17 @@ class AppIdPermissionPolicy : SchemePolicy() {
        }
    }

    // See also SoftRestrictedPermissionPolicy.mayGrantPermission()
    private fun isSoftRestrictedPermissionExemptForPackage(
        packageState: PackageState,
        permissionName: String
    ): Boolean =
        when (permissionName) {
            Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE ->
                packageState.androidPackage!!.targetSdkVersion >= Build.VERSION_CODES.Q
            else -> false
        }

    private inline fun MutateStateScope.anyPackageInAppId(
        appId: Int,
        state: AccessState = newState,
+12 −3
Original line number Diff line number Diff line
@@ -346,9 +346,18 @@ object PermissionFlags {
        return flags.hasBits(RUNTIME_GRANTED)
    }

    fun isAppOpGranted(flags: Int): Boolean =
        isPermissionGranted(flags) && !flags.hasBits(RESTRICTION_REVOKED) &&
            !flags.hasBits(APP_OP_REVOKED)
    fun isAppOpGranted(flags: Int): Boolean {
        if (!isPermissionGranted(flags)) {
            return false
        }
        if (flags.hasAnyBit(MASK_RESTRICTED)) {
            return false
        }
        if (flags.hasBits(APP_OP_REVOKED)) {
            return false
        }
        return true
    }

    fun toApiFlags(flags: Int): Int {
        var apiFlags = 0
+19 −96
Original line number Diff line number Diff line
@@ -88,7 +88,6 @@ import com.android.server.pm.PackageInstallerService
import com.android.server.pm.PackageManagerLocal
import com.android.server.pm.UserManagerInternal
import com.android.server.pm.UserManagerService
import com.android.server.pm.parsing.pkg.AndroidPackageUtils
import com.android.server.pm.permission.LegacyPermission
import com.android.server.pm.permission.LegacyPermissionSettings
import com.android.server.pm.permission.LegacyPermissionState
@@ -97,7 +96,6 @@ import com.android.server.pm.permission.PermissionManagerServiceInterface
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.AndroidPackage
import com.android.server.pm.pkg.PackageState
import com.android.server.policy.SoftRestrictedPermissionPolicy
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.concurrent.CompletableFuture
@@ -1006,16 +1004,6 @@ class PermissionService(private val service: AccessCheckingService) :
        }

        if (isGranted && oldFlags.hasBits(PermissionFlags.SOFT_RESTRICTED)) {
            // TODO: Refactor SoftRestrictedPermissionPolicy.
            val softRestrictedPermissionPolicy =
                SoftRestrictedPermissionPolicy.forPermission(
                    context,
                    AndroidPackageUtils.generateAppInfoWithoutState(androidPackage),
                    androidPackage,
                    UserHandle.of(userId),
                    permissionName
                )
            if (!softRestrictedPermissionPolicy.mayGrantPermission()) {
            if (reportError) {
                Slog.e(
                    LOG_TAG,
@@ -1025,7 +1013,6 @@ class PermissionService(private val service: AccessCheckingService) :
            }
            return
        }
        }

        val newFlags = PermissionFlags.updateRuntimePermissionGranted(oldFlags, isGranted)
        if (oldFlags == newFlags) {
@@ -1850,10 +1837,19 @@ class PermissionService(private val service: AccessCheckingService) :
        allowlistedFlags: Int,
        userId: Int
    ) {
        var exemptMask = 0
        if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM)) {
            exemptMask = exemptMask or PermissionFlags.SYSTEM_EXEMPT
        }
        if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE)) {
            exemptMask = exemptMask or PermissionFlags.UPGRADE_EXEMPT
        }
        if (allowlistedFlags.hasBits(PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER)) {
            exemptMask = exemptMask or PermissionFlags.INSTALLER_EXEMPT
        }

        service.mutateState {
            with(policy) {
                val permissionsFlags = getUidPermissionFlags(appId, userId) ?: return@mutateState

                val permissions = getPermissions()
                androidPackage.requestedPermissions.forEachIndexed { _, requestedPermission ->
                    val permission = permissions[requestedPermission]
@@ -1861,81 +1857,8 @@ class PermissionService(private val service: AccessCheckingService) :
                        return@forEachIndexed
                    }

                    val oldFlags = permissionsFlags[requestedPermission] ?: 0
                    val wasGranted = PermissionFlags.isPermissionGranted(oldFlags)

                    var newFlags = oldFlags
                    var mask = 0
                    var allowlistFlagsCopy = allowlistedFlags
                    while (allowlistFlagsCopy != 0) {
                        val flag = 1 shl allowlistFlagsCopy.countTrailingZeroBits()
                        allowlistFlagsCopy = allowlistFlagsCopy and flag.inv()
                        when (flag) {
                            PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM -> {
                                mask = mask or PermissionFlags.SYSTEM_EXEMPT
                                newFlags =
                                    if (permissionNames.contains(requestedPermission)) {
                                        newFlags or PermissionFlags.SYSTEM_EXEMPT
                                    } else {
                                        newFlags andInv PermissionFlags.SYSTEM_EXEMPT
                                    }
                            }
                            PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE -> {
                                mask = mask or PermissionFlags.UPGRADE_EXEMPT
                                newFlags =
                                    if (permissionNames.contains(requestedPermission)) {
                                        newFlags or PermissionFlags.UPGRADE_EXEMPT
                                    } else {
                                        newFlags andInv PermissionFlags.UPGRADE_EXEMPT
                                    }
                            }
                            PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER -> {
                                mask = mask or PermissionFlags.INSTALLER_EXEMPT
                                newFlags =
                                    if (permissionNames.contains(requestedPermission)) {
                                        newFlags or PermissionFlags.INSTALLER_EXEMPT
                                    } else {
                                        newFlags andInv PermissionFlags.INSTALLER_EXEMPT
                                    }
                            }
                        }
                    }

                    if (oldFlags == newFlags) {
                        return@forEachIndexed
                    }

                    val isExempt = newFlags.hasAnyBit(PermissionFlags.MASK_EXEMPT)

                    // If the permission is policy fixed as granted but it is no longer
                    // on any of the allowlists we need to clear the policy fixed flag
                    // as allowlisting trumps policy i.e. policy cannot grant a non
                    // grantable permission.
                    if (oldFlags.hasBits(PermissionFlags.POLICY_FIXED)) {
                        if (!isExempt && wasGranted) {
                            mask = mask or PermissionFlags.POLICY_FIXED
                            newFlags = newFlags andInv PermissionFlags.POLICY_FIXED
                        }
                    }

                    newFlags =
                        if (permission.isHardRestricted && !isExempt) {
                            newFlags or PermissionFlags.RESTRICTION_REVOKED
                        } else {
                            newFlags andInv PermissionFlags.RESTRICTION_REVOKED
                        }
                    newFlags =
                        if (permission.isSoftRestricted && !isExempt) {
                            newFlags or PermissionFlags.SOFT_RESTRICTED
                        } else {
                            newFlags andInv PermissionFlags.SOFT_RESTRICTED
                        }
                    mask =
                        mask or
                            PermissionFlags.RESTRICTION_REVOKED or
                            PermissionFlags.SOFT_RESTRICTED

                    updatePermissionFlags(appId, userId, requestedPermission, mask, newFlags)
                    var exemptFlags = if (requestedPermission in permissionNames) exemptMask else 0
                    updatePermissionExemptFlags(appId, userId, permission, exemptMask, exemptFlags)
                }
            }
        }
+0 −18
Original line number Diff line number Diff line
@@ -233,24 +233,6 @@ class AppIdPermissionPolicyTest : BasePermissionPolicyTest() {
            .isEqualTo(expectedNewFlags)
    }

    @Test
    fun testOnPackageInstalled_restrictedPermissionsIsExempted_clearsRestrictionFlags() {
        val oldFlags = PermissionFlags.SOFT_RESTRICTED or PermissionFlags.INSTALLER_EXEMPT
        testOnPackageInstalled(
            oldFlags,
            permissionInfoFlags = PermissionInfo.FLAG_SOFT_RESTRICTED
        ) {}
        val actualFlags = getPermissionFlags(APP_ID_1, USER_ID_0, PERMISSION_NAME_0)
        val expectedNewFlags = PermissionFlags.INSTALLER_EXEMPT
        assertWithMessage(
            "After onPackageInstalled() is called for a non-system app that requests a runtime" +
                " soft restricted permission that is exempted. The actual permission flags" +
                " $actualFlags should match the expected flags $expectedNewFlags"
        )
            .that(actualFlags)
            .isEqualTo(expectedNewFlags)
    }

    private fun testOnPackageInstalled(
        oldFlags: Int,
        permissionInfoFlags: Int = 0,