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

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

Merge "Use new disabled package states and permission allowlist."

parents 7d7325f8 52b34e6f
Loading
Loading
Loading
Loading
+34 −20
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.content.Context
import com.android.internal.annotations.Keep
import com.android.server.LocalManagerRegistry
import com.android.server.LocalServices
import com.android.server.SystemConfig
import com.android.server.SystemService
import com.android.server.appop.AppOpsCheckingServiceInterface
import com.android.server.permission.access.appop.AppOpService
@@ -28,7 +29,6 @@ import com.android.server.permission.access.permission.PermissionService
import com.android.server.pm.PackageManagerLocal
import com.android.server.pm.UserManagerService
import com.android.server.pm.permission.PermissionManagerServiceInterface
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.pkg.PackageState

@Keep
@@ -46,6 +46,7 @@ class AccessCheckingService(context: Context) : SystemService(context) {

    private lateinit var packageManagerLocal: PackageManagerLocal
    private lateinit var userManagerService: UserManagerService
    private lateinit var systemConfig: SystemConfig

    override fun onStart() {
        appOpService = AppOpService(this)
@@ -59,12 +60,16 @@ class AccessCheckingService(context: Context) : SystemService(context) {
        packageManagerLocal =
            LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
        userManagerService = UserManagerService.getInstance()
        systemConfig = SystemConfig.getInstance()

        val userIds = IntSet(userManagerService.userIdsIncludingPreCreated)
        val packageStates = packageManagerLocal.packageStates
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        val permissionAllowlist = systemConfig.permissionAllowlist

        val state = AccessState()
        policy.initialize(state, userIds, packageStates)
        policy.initialize(
            state, userIds, packageStates, disabledSystemPackageStates, permissionAllowlist
        )
        persistence.read(state)
        this.state = state

@@ -96,46 +101,55 @@ class AccessCheckingService(context: Context) : SystemService(context) {
    }

    internal fun onStorageVolumeMounted(volumeUuid: String?, isSystemUpdated: Boolean) {
        val packageStates = packageManagerLocal.packageStates
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        mutateState {
            with(policy) { onStorageVolumeMounted(packageStates, volumeUuid, isSystemUpdated) }
            with(policy) {
                onStorageVolumeMounted(
                    packageStates, disabledSystemPackageStates, volumeUuid, isSystemUpdated
                )
            }
        }
    }

    internal fun onPackageAdded(packageName: String) {
        val packageStates = packageManagerLocal.packageStates
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        mutateState {
            with(policy) { onPackageAdded(packageStates, packageName) }
            with(policy) { onPackageAdded(packageStates, disabledSystemPackageStates, packageName) }
        }
    }

    internal fun onPackageRemoved(packageName: String, appId: Int) {
        val packageStates = packageManagerLocal.packageStates
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        mutateState {
            with(policy) { onPackageRemoved(packageStates, packageName, appId) }
            with(policy) {
                onPackageRemoved(packageStates, disabledSystemPackageStates, packageName, appId)
            }
        }
    }

    internal fun onPackageInstalled(
        packageName: String,
        params: PermissionManagerServiceInternal.PackageInstalledParams,
        userId: Int
    ) {
        val packageStates = packageManagerLocal.packageStates
    internal fun onPackageInstalled(packageName: String, userId: Int) {
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        mutateState {
            with(policy) { onPackageInstalled(packageStates, packageName, params, userId) }
            with(policy) {
                onPackageInstalled(packageStates, disabledSystemPackageStates, packageName, userId)
            }
        }
    }

    internal fun onPackageUninstalled(packageName: String, appId: Int, userId: Int) {
        val packageStates = packageManagerLocal.packageStates
        val (packageStates, disabledSystemPackageStates) = packageManagerLocal.allPackageStates
        mutateState {
            with(policy) { onPackageUninstalled(packageStates, packageName, appId, userId) }
            with(policy) {
                onPackageUninstalled(
                    packageStates, disabledSystemPackageStates, packageName, appId, userId
                )
            }
        }
    }

    private val PackageManagerLocal.packageStates: Map<String, PackageState>
        get() = withUnfilteredSnapshot().use { it.packageStates }
    private val PackageManagerLocal.allPackageStates:
        Pair<Map<String, PackageState>, Map<String, PackageState>>
        get() = withUnfilteredSnapshot().use { it.packageStates to it.disabledSystemPackageStates }

    internal inline fun <T> getState(action: GetStateScope.() -> T): T =
        GetStateScope(state).action()
+55 −28
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import com.android.server.permission.access.permission.UidPermissionPolicy
import com.android.server.permission.access.util.forEachTag
import com.android.server.permission.access.util.tag
import com.android.server.permission.access.util.tagName
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.permission.PermissionAllowlist
import com.android.server.pm.pkg.PackageState

class AccessPolicy private constructor(
@@ -54,14 +54,22 @@ class AccessPolicy private constructor(
        with(getSchemePolicy(subject, `object`)) { setDecision(subject, `object`, decision) }
    }

    fun initialize(state: AccessState, userIds: IntSet, packageStates: Map<String, PackageState>) {
    fun initialize(
        state: AccessState,
        userIds: IntSet,
        packageStates: Map<String, PackageState>,
        disabledSystemPackageStates: Map<String, PackageState>,
        permissionAllowlist: PermissionAllowlist
    ) {
        state.systemState.apply {
            this.userIds += userIds
            this.packageStates = packageStates
            this.disabledSystemPackageStates = disabledSystemPackageStates
            packageStates.forEach { (_, packageState) ->
                appIds.getOrPut(packageState.appId) { IndexedListSet() }
                    .add(packageState.packageName)
            }
            this.permissionAllowlist = permissionAllowlist
        }
    }

@@ -83,10 +91,14 @@ class AccessPolicy private constructor(

    fun MutateStateScope.onStorageVolumeMounted(
        packageStates: Map<String, PackageState>,
        disabledSystemPackageStates: Map<String, PackageState>,
        volumeUuid: String?,
        isSystemUpdated: Boolean
    ) {
        newState.systemState.packageStates = packageStates
        newState.systemState.apply {
            this.packageStates = packageStates
            this.disabledSystemPackageStates = disabledSystemPackageStates
        }
        forEachSchemePolicy {
            with(it) { onStorageVolumeMounted(volumeUuid, isSystemUpdated) }
        }
@@ -94,18 +106,24 @@ class AccessPolicy private constructor(

    fun MutateStateScope.onPackageAdded(
        packageStates: Map<String, PackageState>,
        disabledSystemPackageStates: Map<String, PackageState>,
        packageName: String
    ) {
        newState.systemState.packageStates = packageStates
        var isAppIdAdded = false
        val packageState = packageStates[packageName]
        // TODO(zhanghai): Remove check before submission.
        checkNotNull(packageState)
        // TODO(zhanghai): STOPSHIP: Remove check before feature enable.
        checkNotNull(packageState) {
            "Added package $packageName isn't found in packageStates in onPackageAdded()"
        }
        val appId = packageState.appId
        newState.systemState.appIds.getOrPut(appId) {
        var isAppIdAdded = false
        newState.systemState.apply {
            this.packageStates = packageStates
            this.disabledSystemPackageStates = disabledSystemPackageStates
            appIds.getOrPut(appId) {
                isAppIdAdded = true
                IndexedListSet()
            }.add(packageName)
        }
        if (isAppIdAdded) {
            forEachSchemePolicy {
                with(it) { onAppIdAdded(appId) }
@@ -118,18 +136,22 @@ class AccessPolicy private constructor(

    fun MutateStateScope.onPackageRemoved(
        packageStates: Map<String, PackageState>,
        disabledSystemPackageStates: Map<String, PackageState>,
        packageName: String,
        appId: Int
    ) {
        newState.systemState.packageStates = packageStates
        // TODO(zhanghai): STOPSHIP: Remove check before feature enable.
        check(packageName !in packageStates) {
            "Removed package $packageName is still in packageStates in onPackageRemoved()"
        }
        var isAppIdRemoved = false
        // TODO(zhanghai): Remove check before submission.
        check(packageName !in packageStates)
        newState.systemState.appIds.apply appIds@{
            this[appId]?.apply {
        newState.systemState.apply {
            this.packageStates = packageStates
            this.disabledSystemPackageStates = disabledSystemPackageStates
            appIds[appId]?.apply {
                this -= packageName
                if (isEmpty()) {
                    this@appIds -= appId
                    appIds -= appId
                    isAppIdRemoved = true
                }
            }
@@ -146,26 +168,35 @@ class AccessPolicy private constructor(

    fun MutateStateScope.onPackageInstalled(
        packageStates: Map<String, PackageState>,
        disabledSystemPackageStates: Map<String, PackageState>,
        packageName: String,
        params: PermissionManagerServiceInternal.PackageInstalledParams,
        userId: Int
    ) {
        newState.systemState.packageStates = packageStates
        newState.systemState.apply {
            this.packageStates = packageStates
            this.disabledSystemPackageStates = disabledSystemPackageStates
        }
        val packageState = packageStates[packageName]
        // TODO(zhanghai): Remove check before submission.
        checkNotNull(packageState)
        // TODO(zhanghai): STOPSHIP: Remove check before feature enable.
        checkNotNull(packageState) {
            "Installed package $packageName isn't found in packageStates in onPackageInstalled()"
        }
        forEachSchemePolicy {
            with(it) { onPackageInstalled(packageState, params, userId) }
            with(it) { onPackageInstalled(packageState, userId) }
        }
    }

    fun MutateStateScope.onPackageUninstalled(
        packageStates: Map<String, PackageState>,
        disabledSystemPackageStates: Map<String, PackageState>,
        packageName: String,
        appId: Int,
        userId: Int
    ) {
        newState.systemState.packageStates = packageStates
        newState.systemState.apply {
            this.packageStates = packageStates
            this.disabledSystemPackageStates = disabledSystemPackageStates
        }
        forEachSchemePolicy {
            with(it) { onPackageUninstalled(packageName, appId, userId) }
        }
@@ -298,11 +329,7 @@ abstract class SchemePolicy {

    open fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {}

    open fun MutateStateScope.onPackageInstalled(
        packageState: PackageState,
        params: PermissionManagerServiceInternal.PackageInstalledParams,
        userId: Int
    ) {}
    open fun MutateStateScope.onPackageInstalled(packageState: PackageState, userId: Int) {}

    open fun MutateStateScope.onPackageUninstalled(packageName: String, appId: Int, userId: Int) {}

+28 −31
Original line number Diff line number Diff line
@@ -19,15 +19,22 @@ package com.android.server.permission.access
import android.content.pm.PermissionGroupInfo
import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
import com.android.server.permission.access.permission.Permission
import com.android.server.pm.permission.PermissionAllowlist
import com.android.server.pm.pkg.PackageState

class AccessState private constructor(
    val systemState: SystemState,
    val userStates: IntMap<UserState>
) {
    constructor() : this(SystemState(), IntMap())
    constructor() : this(
        SystemState(),
        IntMap()
    )

    fun copy(): AccessState = AccessState(systemState.copy(), userStates.copy { it.copy() })
    fun copy(): AccessState = AccessState(
        systemState.copy(),
        userStates.copy { it.copy() }
    )
}

class SystemState private constructor(
@@ -39,30 +46,26 @@ class SystemState private constructor(
    val knownPackages: IntMap<IndexedListSet<String>>,
    // A map of userId to packageName
    val deviceAndProfileOwners: IntMap<String>,
    // A map of packageName to (A map of oem permission name to whether it's granted)
    val oemPermissions: IndexedMap<String, IndexedMap<String, Boolean>>,
    val privilegedPermissionAllowlistSourcePackageNames: IndexedListSet<String>,
    // A map of packageName to a set of vendor priv app permission names
    val vendorPrivAppPermissions: Map<String, Set<String>>,
    val productPrivAppPermissions: Map<String, Set<String>>,
    val systemExtPrivAppPermissions: Map<String, Set<String>>,
    val privAppPermissions: Map<String, Set<String>>,
    val apexPrivAppPermissions: Map<String, Map<String, Set<String>>>,
    val vendorPrivAppDenyPermissions: Map<String, Set<String>>,
    val productPrivAppDenyPermissions: Map<String, Set<String>>,
    val systemExtPrivAppDenyPermissions: Map<String, Set<String>>,
    val apexPrivAppDenyPermissions: Map<String, Map<String, Set<String>>>,
    val privAppDenyPermissions: Map<String, Set<String>>,
    var permissionAllowlist: PermissionAllowlist,
    val implicitToSourcePermissions: Map<String, Set<String>>,
    val permissionGroups: IndexedMap<String, PermissionGroupInfo>,
    val permissionTrees: IndexedMap<String, Permission>,
    val permissions: IndexedMap<String, Permission>
) : WritableState() {
    constructor() : this(
        IntSet(), emptyMap(), emptyMap(), IntMap(), IntMap(), IntMap(), IndexedMap(),
        IndexedListSet(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(),
        IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(), IndexedMap(),
        IndexedMap(), IndexedMap(), IndexedMap()
        IntSet(),
        emptyMap(),
        emptyMap(),
        IntMap(),
        IntMap(),
        IntMap(),
        IndexedListSet(),
        PermissionAllowlist(),
        IndexedMap(),
        IndexedMap(),
        IndexedMap(),
        IndexedMap()
    )

    fun copy(): SystemState =
@@ -73,18 +76,8 @@ class SystemState private constructor(
            appIds.copy { it.copy() },
            knownPackages.copy { it.copy() },
            deviceAndProfileOwners.copy { it },
            oemPermissions.copy { it.copy { it } },
            privilegedPermissionAllowlistSourcePackageNames.copy(),
            vendorPrivAppPermissions,
            productPrivAppPermissions,
            systemExtPrivAppPermissions,
            privAppPermissions,
            apexPrivAppPermissions,
            vendorPrivAppDenyPermissions,
            productPrivAppDenyPermissions,
            systemExtPrivAppDenyPermissions,
            apexPrivAppDenyPermissions,
            privAppDenyPermissions,
            permissionAllowlist,
            implicitToSourcePermissions,
            permissionGroups.copy { it },
            permissionTrees.copy { it },
@@ -98,7 +91,11 @@ class UserState private constructor(
    val uidAppOpModes: IntMap<IndexedMap<String, Int>>,
    val packageAppOpModes: IndexedMap<String, IndexedMap<String, Int>>
) : WritableState() {
    constructor() : this(IntMap(), IntMap(), IndexedMap())
    constructor() : this(
        IntMap(),
        IntMap(),
        IndexedMap()
    )

    fun copy(): UserState = UserState(
        uidPermissionFlags.copy { it.copy { it } },
+2 −1
Original line number Diff line number Diff line
@@ -435,7 +435,8 @@ class PermissionService(
        } else {
            intArrayOf(userId)
        }
        userIds.forEach { service.onPackageInstalled(androidPackage.packageName, params, it) }
        userIds.forEach { service.onPackageInstalled(androidPackage.packageName, it) }
        // TODO: Handle params.
    }

    override fun onPackageUninstalled(
+41 −58
Original line number Diff line number Diff line
@@ -597,11 +597,9 @@ class UidPermissionPolicy : SchemePolicy() {
            newState.systemState.privilegedPermissionAllowlistSourcePackageNames) {
            return true
        }
        if (isInSystemConfigPrivAppPermissions(androidPackage, permission.name)) {
            return true
        }
        if (isInSystemConfigPrivAppDenyPermissions(androidPackage, permission.name)) {
            return false
        val allowlistState = getPrivilegedPermissionAllowlistState(androidPackage, permission.name)
        if (allowlistState != null) {
            return allowlistState
        }
        // Updated system apps do not need to be allowlisted
        if (packageState.isUpdatedSystemApp) {
@@ -611,66 +609,51 @@ class UidPermissionPolicy : SchemePolicy() {
        return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE
    }

    private fun MutateStateScope.isInSystemConfigPrivAppPermissions(
        androidPackage: AndroidPackage,
        permissionName: String
    ): Boolean {
        // TODO(b/261913353): STOPSHIP: Add AndroidPackage.apexModuleName. The below is only for
        //  passing compilation but won't actually work.
        //val apexModuleName = androidPackage.apexModuleName
        val apexModuleName = androidPackage.packageName
        val systemState = newState.systemState
        val packageName = androidPackage.packageName
        val permissionNames = when {
            androidPackage.isVendor -> systemState.vendorPrivAppPermissions[packageName]
            androidPackage.isProduct -> systemState.productPrivAppPermissions[packageName]
            androidPackage.isSystemExt -> systemState.systemExtPrivAppPermissions[packageName]
            apexModuleName != null -> {
                val apexPrivAppPermissions = systemState.apexPrivAppPermissions[apexModuleName]
                    ?.get(packageName)
                val privAppPermissions = systemState.privAppPermissions[packageName]
                when {
                    apexPrivAppPermissions == null -> privAppPermissions
                    privAppPermissions == null -> apexPrivAppPermissions
                    else -> apexPrivAppPermissions + privAppPermissions
                }
            }
            else -> systemState.privAppPermissions[packageName]
        }
        return permissionNames?.contains(permissionName) == true
    }

    private fun MutateStateScope.isInSystemConfigPrivAppDenyPermissions(
    /**
     * Get the whether a privileged permission is explicitly allowed or denied for a package in the
     * allowlist, or `null` if it's not in the allowlist.
     */
    private fun MutateStateScope.getPrivilegedPermissionAllowlistState(
        androidPackage: AndroidPackage,
        permissionName: String
    ): Boolean {
        // Different from the previous implementation, which may incorrectly use the APEX package
        // name, we now use the APEX module name to be consistent with the allowlist.
    ): Boolean? {
        val permissionAllowlist = newState.systemState.permissionAllowlist
        // TODO(b/261913353): STOPSHIP: Add AndroidPackage.apexModuleName. The below is only for
        //  passing compilation but won't actually work.
        //val apexModuleName = androidPackage.apexModuleName
        val apexModuleName = androidPackage.packageName
        val systemState = newState.systemState
        val packageName = androidPackage.packageName
        val permissionNames = when {
            androidPackage.isVendor -> systemState.vendorPrivAppDenyPermissions[packageName]
            androidPackage.isProduct -> systemState.productPrivAppDenyPermissions[packageName]
            androidPackage.isSystemExt -> systemState.systemExtPrivAppDenyPermissions[packageName]
            // Different from the previous implementation, which ignores the regular priv app
            // denylist in this case, we now respect it as well to be consistent with the allowlist.
        return when {
            androidPackage.isVendor -> permissionAllowlist.getVendorPrivilegedAppAllowlistState(
                packageName, permissionName
            )
            androidPackage.isProduct -> permissionAllowlist.getProductPrivilegedAppAllowlistState(
                packageName, permissionName
            )
            androidPackage.isSystemExt ->
                permissionAllowlist.getSystemExtPrivilegedAppAllowlistState(
                    packageName, permissionName
                )
            apexModuleName != null -> {
                val apexPrivAppDenyPermissions = systemState
                    .apexPrivAppDenyPermissions[apexModuleName]?.get(packageName)
                val privAppDenyPermissions = systemState.privAppDenyPermissions[packageName]
                when {
                    apexPrivAppDenyPermissions == null -> privAppDenyPermissions
                    privAppDenyPermissions == null -> apexPrivAppDenyPermissions
                    else -> apexPrivAppDenyPermissions + privAppDenyPermissions
                val nonApexAllowlistState = permissionAllowlist.getPrivilegedAppAllowlistState(
                    packageName, permissionName
                )
                if (nonApexAllowlistState != null) {
                    // TODO(andreionea): Remove check as soon as all apk-in-apex
                    // permission allowlists are migrated.
                    Log.w(
                        LOG_TAG, "Package $packageName is an APK in APEX but has permission" +
                            " allowlist on the system image, please bundle the allowlist in the" +
                            " $apexModuleName APEX instead"
                    )
                }
                val apexAllowlistState = permissionAllowlist.getApexPrivilegedAppAllowlistState(
                    apexModuleName, packageName, permissionName
                )
                apexAllowlistState ?: nonApexAllowlistState
            }
            else -> systemState.privAppDenyPermissions[packageName]
            else -> permissionAllowlist.getPrivilegedAppAllowlistState(packageName, permissionName)
        }
        return permissionNames?.contains(permissionName) == true
    }

    private fun MutateStateScope.anyPackageInAppId(
@@ -811,13 +794,13 @@ class UidPermissionPolicy : SchemePolicy() {
            }
            permission.isOem -> {
                if (androidPackage.isOem) {
                    val isOemAllowlisted = newState.systemState
                        .oemPermissions[packageName]?.get(permissionName)
                    checkNotNull(isOemAllowlisted) {
                    val allowlistState = newState.systemState.permissionAllowlist
                        .getOemAppAllowlistState(packageName, permissionName)
                    checkNotNull(allowlistState) {
                        "OEM permission $permissionName requested by package" +
                            " $packageName must be explicitly declared granted or not"
                    }
                    return isOemAllowlisted
                    return allowlistState
                }
            }
        }