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

Commit 20b04c7f authored by Hai Zhang's avatar Hai Zhang
Browse files

Add permission flag related methods.

Implemented methods for checking/updating permission state and
checking/updating permission flags.

Different from the old implementation, the new code has been
re-written to cleanly check or not check caller's privileges. external
facing methods will enforce necessary permissions, and then will only
call internal methods that no longer enforces permissions.

The new code also tries to gets the package state, and gets or mutates
the permission state, for only once. This ensures we are at least
consistent within package or permission.

The methods have also be restructured to do:
1. Enforce cross-user permissions.
2. Enforce method-related permissions.
3. Skip if user is not found (may happen upon user deletion).
4. Gather package state, get or mutate permission state, or call into
    internal methods that doesn't enforce caller permissions.

Log statements have also been prefixed with method names to make
debugging either - whereas exceptions already have its stacktrace.

PermissionFlags now also takes in the Permission object and correctly
handles restricted permissions, so that the restricted permission
allowlist implementation can now call it directly.

Bug: 252884423
Test: presubmit
Change-Id: Ide19bb2e286123e3c81f641f114461fcd2c04a04
parent 4b8c2445
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -148,10 +148,21 @@ inline fun <K, V> IndexedMap<K, V>.retainAllIndexed(predicate: (Int, K, V) -> Bo
    return isChanged
}

inline fun <K, V, R> IndexedMap<K, V>.mapNotNullIndexed(transform: (K, V) -> R?): IndexedList<R> =
inline fun <K, V, R> IndexedMap<K, V>.mapNotNullIndexed(
    transform: (Int, K, V) -> R?
): IndexedList<R> =
    IndexedList<R>().also { destination ->
        forEachIndexed { _, key, value ->
            transform(key, value)?.let { destination += it }
        forEachIndexed { index, key, value ->
            transform(index, key, value)?.let { destination += it }
        }
    }

inline fun <K, V, R> IndexedMap<K, V>.mapNotNullIndexedToSet(
    transform: (Int, K, V) -> R?
): IndexedSet<R> =
    IndexedSet<R>().also { destination ->
        forEachIndexed { index, key, value ->
            transform(index, key, value)?.let { destination += it }
        }
    }

+74 −82
Original line number Diff line number Diff line
@@ -317,172 +317,164 @@ object PermissionFlags {
     */
    const val MASK_EXEMPT = INSTALLER_EXEMPT or SYSTEM_EXEMPT or UPGRADE_EXEMPT

    /**
     * Mask for all API permission flags about permission restriction.
     */
    private const val API_MASK_RESTRICTION =
        PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT or
            PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT or
            PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT or
            PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION

    /**
     * Mask for all permission flags about permission restriction.
     */
    private const val MASK_RESTRICTION = INSTALLER_EXEMPT or SYSTEM_EXEMPT or
        UPGRADE_EXEMPT or RESTRICTION_REVOKED or SOFT_RESTRICTED

    fun isPermissionGranted(policyFlags: Int): Boolean {
        if (policyFlags.hasBits(INSTALL_GRANTED)) {
    fun isPermissionGranted(flags: Int): Boolean {
        if (flags.hasBits(INSTALL_GRANTED)) {
            return true
        }
        if (policyFlags.hasBits(INSTALL_REVOKED)) {
        if (flags.hasBits(INSTALL_REVOKED)) {
            return false
        }
        if (policyFlags.hasBits(PROTECTION_GRANTED)) {
        if (flags.hasBits(PROTECTION_GRANTED)) {
            return true
        }
        if (policyFlags.hasBits(LEGACY_GRANTED) || policyFlags.hasBits(IMPLICIT_GRANTED)) {
        if (flags.hasBits(LEGACY_GRANTED) || flags.hasBits(IMPLICIT_GRANTED)) {
            return true
        }
        if (policyFlags.hasBits(RESTRICTION_REVOKED)) {
        if (flags.hasBits(RESTRICTION_REVOKED)) {
            return false
        }
        return policyFlags.hasBits(RUNTIME_GRANTED)
        return flags.hasBits(RUNTIME_GRANTED)
    }

    fun isAppOpGranted(policyFlags: Int): Boolean =
        isPermissionGranted(policyFlags) && !policyFlags.hasBits(APP_OP_REVOKED)

    fun isReviewRequired(policyFlags: Int): Boolean =
        policyFlags.hasBits(LEGACY_GRANTED) && policyFlags.hasBits(IMPLICIT)
    fun isAppOpGranted(flags: Int): Boolean =
        isPermissionGranted(flags) && !flags.hasBits(APP_OP_REVOKED)

    fun toApiFlags(policyFlags: Int): Int {
    fun toApiFlags(flags: Int): Int {
        var apiFlags = 0
        if (policyFlags.hasBits(USER_SET)) {
        if (flags.hasBits(USER_SET)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_SET
        }
        if (policyFlags.hasBits(USER_FIXED)) {
        if (flags.hasBits(USER_FIXED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_FIXED
        }
        if (policyFlags.hasBits(POLICY_FIXED)) {
        if (flags.hasBits(POLICY_FIXED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_POLICY_FIXED
        }
        if (policyFlags.hasBits(SYSTEM_FIXED)) {
        if (flags.hasBits(SYSTEM_FIXED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
        }
        if (policyFlags.hasBits(PREGRANT)) {
        if (flags.hasBits(PREGRANT)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT
        }
        if (policyFlags.hasBits(IMPLICIT)) {
            apiFlags = apiFlags or if (policyFlags.hasBits(LEGACY_GRANTED)) {
        if (flags.hasBits(IMPLICIT)) {
            apiFlags = apiFlags or if (flags.hasBits(LEGACY_GRANTED)) {
                PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
            } else {
                PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
            }
        }
        if (policyFlags.hasBits(USER_SENSITIVE_WHEN_GRANTED)) {
        if (flags.hasBits(USER_SENSITIVE_WHEN_GRANTED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED
        }
        if (policyFlags.hasBits(USER_SENSITIVE_WHEN_REVOKED)) {
        if (flags.hasBits(USER_SENSITIVE_WHEN_REVOKED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED
        }
        if (policyFlags.hasBits(INSTALLER_EXEMPT)) {
        if (flags.hasBits(INSTALLER_EXEMPT)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT
        }
        if (policyFlags.hasBits(SYSTEM_EXEMPT)) {
        if (flags.hasBits(SYSTEM_EXEMPT)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
        }
        if (policyFlags.hasBits(UPGRADE_EXEMPT)) {
        if (flags.hasBits(UPGRADE_EXEMPT)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
        }
        if (policyFlags.hasBits(RESTRICTION_REVOKED) || policyFlags.hasBits(SOFT_RESTRICTED)) {
        if (flags.hasBits(RESTRICTION_REVOKED) || flags.hasBits(SOFT_RESTRICTED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION
        }
        if (policyFlags.hasBits(ROLE)) {
        if (flags.hasBits(ROLE)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE
        }
        if (policyFlags.hasBits(APP_OP_REVOKED)) {
        if (flags.hasBits(APP_OP_REVOKED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_REVOKED_COMPAT
        }
        if (policyFlags.hasBits(ONE_TIME)) {
        if (flags.hasBits(ONE_TIME)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_ONE_TIME
        }
        if (policyFlags.hasBits(HIBERNATION)) {
        if (flags.hasBits(HIBERNATION)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_AUTO_REVOKED
        }
        if (policyFlags.hasBits(USER_SELECTED)) {
        if (flags.hasBits(USER_SELECTED)) {
            apiFlags = apiFlags or PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY
        }
        return apiFlags
    }

    fun setRuntimePermissionGranted(policyFlags: Int, isGranted: Boolean): Int =
        if (isGranted) policyFlags or RUNTIME_GRANTED else policyFlags andInv RUNTIME_GRANTED
    fun updateRuntimePermissionGranted(flags: Int, isGranted: Boolean): Int =
        if (isGranted) flags or RUNTIME_GRANTED else flags andInv RUNTIME_GRANTED

    fun updatePolicyFlags(policyFlags: Int, apiFlagMask: Int, apiFlagValues: Int): Int {
        check(!apiFlagMask.hasAnyBit(API_MASK_RESTRICTION)) {
            "Permission flags about permission restriction can only be directly mutated by the" +
                " policy"
        }
        val oldApiFlags = toApiFlags(policyFlags)
    fun updateFlags(permission: Permission, flags: Int, apiFlagMask: Int, apiFlagValues: Int): Int {
        val oldApiFlags = toApiFlags(flags)
        val newApiFlags = (oldApiFlags andInv apiFlagMask) or (apiFlagValues and apiFlagMask)
        return toPolicyFlags(policyFlags, newApiFlags)
        return fromApiFlags(newApiFlags, permission, flags)
    }

    private fun toPolicyFlags(oldPolicyFlags: Int, apiFlags: Int): Int {
        var policyFlags = 0
        policyFlags = policyFlags or (oldPolicyFlags and INSTALL_GRANTED)
        policyFlags = policyFlags or (oldPolicyFlags and INSTALL_REVOKED)
        policyFlags = policyFlags or (oldPolicyFlags and PROTECTION_GRANTED)
    private fun fromApiFlags(apiFlags: Int, permission: Permission, oldFlags: Int): Int {
        var flags = 0
        flags = flags or (oldFlags and INSTALL_GRANTED)
        flags = flags or (oldFlags and INSTALL_REVOKED)
        flags = flags or (oldFlags and PROTECTION_GRANTED)
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE)) {
            policyFlags = policyFlags or ROLE
            flags = flags or ROLE
        }
        policyFlags = policyFlags or (oldPolicyFlags and RUNTIME_GRANTED)
        flags = flags or (oldFlags and RUNTIME_GRANTED)
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_SET)) {
            policyFlags = policyFlags or USER_SET
            flags = flags or USER_SET
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_FIXED)) {
            policyFlags = policyFlags or USER_FIXED
            flags = flags or USER_FIXED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_POLICY_FIXED)) {
            policyFlags = policyFlags or POLICY_FIXED
            flags = flags or POLICY_FIXED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_SYSTEM_FIXED)) {
            policyFlags = policyFlags or SYSTEM_FIXED
            flags = flags or SYSTEM_FIXED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT)) {
            policyFlags = policyFlags or PREGRANT
            flags = flags or PREGRANT
        }
        policyFlags = policyFlags or (oldPolicyFlags and LEGACY_GRANTED)
        policyFlags = policyFlags or (oldPolicyFlags and IMPLICIT_GRANTED)
        flags = flags or (oldFlags and LEGACY_GRANTED)
        flags = flags or (oldFlags and IMPLICIT_GRANTED)
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) ||
            apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVOKE_WHEN_REQUESTED)) {
            policyFlags = policyFlags or IMPLICIT
            flags = flags or IMPLICIT
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED)) {
            policyFlags = policyFlags or USER_SENSITIVE_WHEN_GRANTED
            flags = flags or USER_SENSITIVE_WHEN_GRANTED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED)) {
            policyFlags = policyFlags or USER_SENSITIVE_WHEN_REVOKED
            flags = flags or USER_SENSITIVE_WHEN_REVOKED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT)) {
            flags = flags or INSTALLER_EXEMPT
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT)) {
            flags = flags or SYSTEM_EXEMPT
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT)) {
            flags = flags or UPGRADE_EXEMPT
        }
        // We ignore whether FLAG_PERMISSION_APPLY_RESTRICTION is set here because previously
        // platform may be relying on the old restorePermissionState() to get it correct later.
        if (!flags.hasAnyBit(MASK_EXEMPT)) {
            if (permission.isHardRestricted) {
                flags = flags or RESTRICTION_REVOKED
            }
            if (permission.isSoftRestricted) {
                flags = flags or SOFT_RESTRICTED
            }
        }
        // FLAG_PERMISSION_APPLY_RESTRICTION can be either REVOKED_BY_RESTRICTION when the
        // permission is hard restricted, or SOFT_RESTRICTED when the permission is soft restricted.
        // However since we should never allow indirect mutation of restriction state, we can just
        // get the flags about restriction from the old policy flags.
        policyFlags = policyFlags or (oldPolicyFlags and MASK_RESTRICTION)
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_REVOKED_COMPAT)) {
            policyFlags = policyFlags or APP_OP_REVOKED
            flags = flags or APP_OP_REVOKED
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_ONE_TIME)) {
            policyFlags = policyFlags or ONE_TIME
            flags = flags or ONE_TIME
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_AUTO_REVOKED)) {
            policyFlags = policyFlags or HIBERNATION
            flags = flags or HIBERNATION
        }
        if (apiFlags.hasBits(PackageManager.FLAG_PERMISSION_SELECTED_LOCATION_ACCURACY)) {
            policyFlags = policyFlags or USER_SELECTED
            flags = flags or USER_SELECTED
        }
        return policyFlags
        return flags
    }
}
+939 −156

File changed.

Preview size limit exceeded, changes collapsed.

+29 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.permission.access.util

import android.os.Binder
import kotlin.reflect.KClass

inline fun <R> KClass<Binder>.withClearedCallingIdentity(action: () -> R): R {
    val token = Binder.clearCallingIdentity()
    try {
        return action()
    } finally {
        Binder.restoreCallingIdentity(token)
    }
}