1 /*
<lambda>null2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.permission.access
18 
19 import android.util.Slog
20 import com.android.modules.utils.BinaryXmlPullParser
21 import com.android.modules.utils.BinaryXmlSerializer
22 import com.android.server.SystemConfig
23 import com.android.server.permission.access.appop.AppIdAppOpPolicy
24 import com.android.server.permission.access.appop.PackageAppOpPolicy
25 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
26 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports
27 import com.android.server.permission.access.immutable.IndexedMap
28 import com.android.server.permission.access.permission.AppIdPermissionPolicy
29 import com.android.server.permission.access.permission.DevicePermissionPolicy
30 import com.android.server.permission.access.util.attributeInt
31 import com.android.server.permission.access.util.attributeInterned
32 import com.android.server.permission.access.util.forEachTag
33 import com.android.server.permission.access.util.getAttributeIntOrThrow
34 import com.android.server.permission.access.util.getAttributeValueOrThrow
35 import com.android.server.permission.access.util.tag
36 import com.android.server.permission.access.util.tagName
37 import com.android.server.pm.permission.PermissionAllowlist
38 import com.android.server.pm.pkg.PackageState
39 
40 class AccessPolicy
41 private constructor(
42     private val schemePolicies: IndexedMap<String, IndexedMap<String, SchemePolicy>>
43 ) {
44     @Suppress("UNCHECKED_CAST")
45     constructor() :
46         this(
47             MutableIndexedMap<String, MutableIndexedMap<String, SchemePolicy>>().apply {
48                 fun addPolicy(policy: SchemePolicy) {
49                     getOrPut(policy.subjectScheme) { MutableIndexedMap() }[policy.objectScheme] =
50                         policy
51                 }
52                 addPolicy(AppIdPermissionPolicy())
53                 addPolicy(DevicePermissionPolicy())
54                 addPolicy(AppIdAppOpPolicy())
55                 addPolicy(PackageAppOpPolicy())
56             } as IndexedMap<String, IndexedMap<String, SchemePolicy>>
57         )
58 
59     fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy =
60         checkNotNull(schemePolicies[subjectScheme]?.get(objectScheme)) {
61             "Scheme policy for $subjectScheme and $objectScheme does not exist"
62         }
63 
64     fun initialize(
65         state: MutableAccessState,
66         userIds: IntSet,
67         packageStates: Map<String, PackageState>,
68         disabledSystemPackageStates: Map<String, PackageState>,
69         knownPackages: IntMap<Array<String>>,
70         isLeanback: Boolean,
71         configPermissions: Map<String, SystemConfig.PermissionEntry>,
72         privilegedPermissionAllowlistPackages: IndexedListSet<String>,
73         permissionAllowlist: PermissionAllowlist,
74         implicitToSourcePermissions: IndexedMap<String, IndexedListSet<String>>
75     ) {
76         state.mutateExternalState().apply {
77             mutateUserIds() += userIds
78             setPackageStates(packageStates)
79             setDisabledSystemPackageStates(disabledSystemPackageStates)
80             packageStates.forEach { (_, packageState) ->
81                 if (packageState.isApex) {
82                     return@forEach
83                 }
84                 mutateAppIdPackageNames()
85                     .mutateOrPut(packageState.appId) { MutableIndexedListSet() }
86                     .add(packageState.packageName)
87             }
88             setKnownPackages(knownPackages)
89             setLeanback(isLeanback)
90             setConfigPermissions(configPermissions)
91             setPrivilegedPermissionAllowlistPackages(privilegedPermissionAllowlistPackages)
92             setPermissionAllowlist(permissionAllowlist)
93             setImplicitToSourcePermissions(implicitToSourcePermissions)
94         }
95         state.mutateUserStatesNoWrite().apply {
96             userIds.forEachIndexed { _, userId -> this[userId] = MutableUserState() }
97         }
98     }
99 
100     fun GetStateScope.onStateMutated() {
101         forEachSchemePolicy { with(it) { onStateMutated() } }
102     }
103 
104     fun MutateStateScope.onUserAdded(userId: Int) {
105         newState.mutateExternalState().mutateUserIds() += userId
106         newState.mutateUserStatesNoWrite()[userId] = MutableUserState()
107         forEachSchemePolicy { with(it) { onUserAdded(userId) } }
108         newState.externalState.packageStates.forEach { (_, packageState) ->
109             if (packageState.isApex) {
110                 return@forEach
111             }
112             upgradePackageVersion(packageState, userId)
113         }
114     }
115 
116     fun MutateStateScope.onUserRemoved(userId: Int) {
117         newState.mutateExternalState().mutateUserIds() -= userId
118         newState.mutateUserStatesNoWrite() -= userId
119         forEachSchemePolicy { with(it) { onUserRemoved(userId) } }
120     }
121 
122     fun MutateStateScope.onStorageVolumeMounted(
123         packageStates: Map<String, PackageState>,
124         disabledSystemPackageStates: Map<String, PackageState>,
125         knownPackages: IntMap<Array<String>>,
126         volumeUuid: String?,
127         packageNames: List<String>,
128         isSystemUpdated: Boolean
129     ) {
130         val addedAppIds = MutableIntSet()
131         newState.mutateExternalState().apply {
132             setPackageStates(packageStates)
133             setDisabledSystemPackageStates(disabledSystemPackageStates)
134             packageStates.forEach { (packageName, packageState) ->
135                 if (packageState.isApex) {
136                     return@forEach
137                 }
138                 if (packageState.volumeUuid == volumeUuid) {
139                     // The APK for a package on a mounted storage volume may still be unavailable
140                     // due to APK being deleted, e.g. after an OTA.
141                     check(
142                         packageState.androidPackage == null || packageNames.contains(packageName)
143                     ) {
144                         "Package $packageName on storage volume $volumeUuid didn't receive" +
145                             " onPackageAdded() before onStorageVolumeMounted()"
146                     }
147                     val appId = packageState.appId
148                     mutateAppIdPackageNames().mutateOrPut(appId) {
149                         addedAppIds += appId
150                         MutableIndexedListSet()
151                     } += packageName
152                 }
153             }
154             setKnownPackages(knownPackages)
155         }
156         addedAppIds.forEachIndexed { _, appId ->
157             forEachSchemePolicy { with(it) { onAppIdAdded(appId) } }
158         }
159         forEachSchemePolicy {
160             with(it) { onStorageVolumeMounted(volumeUuid, packageNames, isSystemUpdated) }
161         }
162         packageStates.forEach { (_, packageState) ->
163             if (packageState.isApex) {
164                 return@forEach
165             }
166             if (packageState.volumeUuid == volumeUuid) {
167                 newState.userStates.forEachIndexed { _, userId, _ ->
168                     upgradePackageVersion(packageState, userId)
169                 }
170             }
171         }
172     }
173 
174     fun MutateStateScope.onPackageAdded(
175         packageStates: Map<String, PackageState>,
176         disabledSystemPackageStates: Map<String, PackageState>,
177         knownPackages: IntMap<Array<String>>,
178         packageName: String
179     ) {
180         val packageState = packageStates[packageName]
181         checkNotNull(packageState) {
182             "Added package $packageName isn't found in packageStates in onPackageAdded()"
183         }
184         val appId = packageState.appId
185         var isAppIdAdded = false
186         newState.mutateExternalState().apply {
187             setPackageStates(packageStates)
188             setDisabledSystemPackageStates(disabledSystemPackageStates)
189             mutateAppIdPackageNames().mutateOrPut(appId) {
190                 isAppIdAdded = true
191                 MutableIndexedListSet()
192             } += packageName
193             setKnownPackages(knownPackages)
194         }
195         if (isAppIdAdded) {
196             forEachSchemePolicy { with(it) { onAppIdAdded(appId) } }
197         }
198         forEachSchemePolicy { with(it) { onPackageAdded(packageState) } }
199         newState.userStates.forEachIndexed { _, userId, _ ->
200             upgradePackageVersion(packageState, userId)
201         }
202     }
203 
204     fun MutateStateScope.onPackageRemoved(
205         packageStates: Map<String, PackageState>,
206         disabledSystemPackageStates: Map<String, PackageState>,
207         knownPackages: IntMap<Array<String>>,
208         packageName: String,
209         appId: Int
210     ) {
211         check(packageName !in packageStates) {
212             "Removed package $packageName is still in packageStates in onPackageRemoved()"
213         }
214         var isAppIdRemoved = false
215         newState.mutateExternalState().apply {
216             setPackageStates(packageStates)
217             setDisabledSystemPackageStates(disabledSystemPackageStates)
218             mutateAppIdPackageNames().mutate(appId)?.apply {
219                 this -= packageName
220                 if (isEmpty()) {
221                     mutateAppIdPackageNames() -= appId
222                     isAppIdRemoved = true
223                 }
224             }
225             setKnownPackages(knownPackages)
226         }
227         forEachSchemePolicy { with(it) { onPackageRemoved(packageName, appId) } }
228         if (isAppIdRemoved) {
229             forEachSchemePolicy { with(it) { onAppIdRemoved(appId) } }
230         }
231         newState.userStates.forEachIndexed { userStateIndex, _, userState ->
232             if (packageName in userState.packageVersions) {
233                 newState.mutateUserStateAt(userStateIndex).mutatePackageVersions() -= packageName
234             }
235         }
236     }
237 
238     fun MutateStateScope.onPackageInstalled(
239         packageStates: Map<String, PackageState>,
240         disabledSystemPackageStates: Map<String, PackageState>,
241         knownPackages: IntMap<Array<String>>,
242         packageName: String,
243         userId: Int
244     ) {
245         newState.mutateExternalState().apply {
246             setPackageStates(packageStates)
247             setDisabledSystemPackageStates(disabledSystemPackageStates)
248             setKnownPackages(knownPackages)
249         }
250         val packageState = packageStates[packageName]
251         checkNotNull(packageState) {
252             "Installed package $packageName isn't found in packageStates in onPackageInstalled()"
253         }
254         forEachSchemePolicy { with(it) { onPackageInstalled(packageState, userId) } }
255     }
256 
257     fun MutateStateScope.onPackageUninstalled(
258         packageStates: Map<String, PackageState>,
259         disabledSystemPackageStates: Map<String, PackageState>,
260         knownPackages: IntMap<Array<String>>,
261         packageName: String,
262         appId: Int,
263         userId: Int
264     ) {
265         newState.mutateExternalState().apply {
266             setPackageStates(packageStates)
267             setDisabledSystemPackageStates(disabledSystemPackageStates)
268             setKnownPackages(knownPackages)
269         }
270         forEachSchemePolicy { with(it) { onPackageUninstalled(packageName, appId, userId) } }
271     }
272 
273     fun MutateStateScope.onSystemReady() {
274         newState.mutateExternalState().setSystemReady(true)
275         forEachSchemePolicy { with(it) { onSystemReady() } }
276     }
277 
278     fun migrateSystemState(state: MutableAccessState) {
279         forEachSchemePolicy { with(it) { migrateSystemState(state) } }
280     }
281 
282     fun migrateUserState(state: MutableAccessState, userId: Int) {
283         forEachSchemePolicy { with(it) { migrateUserState(state, userId) } }
284     }
285 
286     private fun MutateStateScope.upgradePackageVersion(packageState: PackageState, userId: Int) {
287         if (packageState.androidPackage == null) {
288             return
289         }
290 
291         val packageName = packageState.packageName
292         // The version would be latest when the package is new to the system, e.g. newly
293         // installed, first boot, or system apps added via OTA.
294         val version = newState.userStates[userId]!!.packageVersions[packageName]
295         when {
296             version == null ->
297                 newState.mutateUserState(userId)!!.mutatePackageVersions()[packageName] =
298                     VERSION_LATEST
299             version < VERSION_LATEST -> {
300                 forEachSchemePolicy {
301                     with(it) { upgradePackageState(packageState, userId, version) }
302                 }
303                 newState.mutateUserState(userId)!!.mutatePackageVersions()[packageName] =
304                     VERSION_LATEST
305             }
306             version == VERSION_LATEST -> {}
307             else ->
308                 Slog.w(
309                     LOG_TAG,
310                     "Unexpected version $version for package $packageName," +
311                         "latest version is $VERSION_LATEST"
312                 )
313         }
314     }
315 
316     fun BinaryXmlPullParser.parseSystemState(state: MutableAccessState) {
317         forEachTag {
318             when (tagName) {
319                 TAG_ACCESS -> {
320                     forEachTag { forEachSchemePolicy { with(it) { parseSystemState(state) } } }
321                 }
322                 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $tagName when parsing system state")
323             }
324         }
325     }
326 
327     fun BinaryXmlSerializer.serializeSystemState(state: AccessState) {
328         tag(TAG_ACCESS) { forEachSchemePolicy { with(it) { serializeSystemState(state) } } }
329     }
330 
331     fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
332         forEachTag {
333             when (tagName) {
334                 TAG_ACCESS -> {
335                     forEachTag {
336                         when (tagName) {
337                             TAG_PACKAGE_VERSIONS -> parsePackageVersions(state, userId)
338                             TAG_DEFAULT_PERMISSION_GRANT ->
339                                 parseDefaultPermissionGrant(state, userId)
340                             else -> {
341                                 forEachSchemePolicy { with(it) { parseUserState(state, userId) } }
342                             }
343                         }
344                     }
345                 }
346                 else -> {
347                     Slog.w(
348                         LOG_TAG,
349                         "Ignoring unknown tag $tagName when parsing user state for user $userId"
350                     )
351                 }
352             }
353         }
354     }
355 
356     private fun BinaryXmlPullParser.parsePackageVersions(state: MutableAccessState, userId: Int) {
357         val userState = state.mutateUserState(userId, WriteMode.NONE)!!
358         val packageVersions = userState.mutatePackageVersions()
359         forEachTag {
360             when (tagName) {
361                 TAG_PACKAGE -> parsePackageVersion(packageVersions)
362                 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing package versions")
363             }
364         }
365         packageVersions.forEachReversedIndexed { packageVersionIndex, packageName, _ ->
366             if (packageName !in state.externalState.packageStates) {
367                 Slog.w(LOG_TAG, "Dropping unknown $packageName when parsing package versions")
368                 packageVersions.removeAt(packageVersionIndex)
369                 userState.requestWriteMode(WriteMode.ASYNCHRONOUS)
370             }
371         }
372     }
373 
374     private fun BinaryXmlPullParser.parsePackageVersion(
375         packageVersions: MutableIndexedMap<String, Int>
376     ) {
377         val packageName = getAttributeValueOrThrow(ATTR_NAME).intern()
378         val version = getAttributeIntOrThrow(ATTR_VERSION)
379         packageVersions[packageName] = version
380     }
381 
382     private fun BinaryXmlPullParser.parseDefaultPermissionGrant(
383         state: MutableAccessState,
384         userId: Int
385     ) {
386         val userState = state.mutateUserState(userId, WriteMode.NONE)!!
387         val fingerprint = getAttributeValueOrThrow(ATTR_FINGERPRINT).intern()
388         userState.setDefaultPermissionGrantFingerprint(fingerprint)
389     }
390 
391     fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
392         tag(TAG_ACCESS) {
393             serializePackageVersions(state.userStates[userId]!!.packageVersions)
394             serializeDefaultPermissionGrantFingerprint(
395                 state.userStates[userId]!!.defaultPermissionGrantFingerprint
396             )
397             forEachSchemePolicy { with(it) { serializeUserState(state, userId) } }
398         }
399     }
400 
401     private fun BinaryXmlSerializer.serializePackageVersions(
402         packageVersions: IndexedMap<String, Int>
403     ) {
404         tag(TAG_PACKAGE_VERSIONS) {
405             packageVersions.forEachIndexed { _, packageName, version ->
406                 tag(TAG_PACKAGE) {
407                     attributeInterned(ATTR_NAME, packageName)
408                     attributeInt(ATTR_VERSION, version)
409                 }
410             }
411         }
412     }
413 
414     private fun BinaryXmlSerializer.serializeDefaultPermissionGrantFingerprint(
415         fingerprint: String?
416     ) {
417         if (fingerprint != null) {
418             tag(TAG_DEFAULT_PERMISSION_GRANT) { attributeInterned(ATTR_FINGERPRINT, fingerprint) }
419         }
420     }
421 
422     private fun getSchemePolicy(subject: AccessUri, `object`: AccessUri): SchemePolicy =
423         getSchemePolicy(subject.scheme, `object`.scheme)
424 
425     private inline fun forEachSchemePolicy(action: (SchemePolicy) -> Unit) {
426         schemePolicies.forEachIndexed { _, _, objectSchemePolicies ->
427             objectSchemePolicies.forEachIndexed { _, _, schemePolicy -> action(schemePolicy) }
428         }
429     }
430 
431     companion object {
432         private val LOG_TAG = AccessPolicy::class.java.simpleName
433 
434         internal const val VERSION_LATEST = 15
435 
436         private const val TAG_ACCESS = "access"
437         private const val TAG_DEFAULT_PERMISSION_GRANT = "default-permission-grant"
438         private const val TAG_PACKAGE_VERSIONS = "package-versions"
439         private const val TAG_PACKAGE = "package"
440 
441         private const val ATTR_FINGERPRINT = "fingerprint"
442         private const val ATTR_NAME = "name"
443         private const val ATTR_VERSION = "version"
444     }
445 }
446 
447 abstract class SchemePolicy {
448     abstract val subjectScheme: String
449 
450     abstract val objectScheme: String
451 
onStateMutatednull452     open fun GetStateScope.onStateMutated() {}
453 
onUserAddednull454     open fun MutateStateScope.onUserAdded(userId: Int) {}
455 
onUserRemovednull456     open fun MutateStateScope.onUserRemoved(userId: Int) {}
457 
onAppIdAddednull458     open fun MutateStateScope.onAppIdAdded(appId: Int) {}
459 
onAppIdRemovednull460     open fun MutateStateScope.onAppIdRemoved(appId: Int) {}
461 
onStorageVolumeMountednull462     open fun MutateStateScope.onStorageVolumeMounted(
463         volumeUuid: String?,
464         packageNames: List<String>,
465         isSystemUpdated: Boolean,
466     ) {}
467 
onPackageAddednull468     open fun MutateStateScope.onPackageAdded(packageState: PackageState) {}
469 
onPackageRemovednull470     open fun MutateStateScope.onPackageRemoved(packageName: String, appId: Int) {}
471 
onPackageInstallednull472     open fun MutateStateScope.onPackageInstalled(packageState: PackageState, userId: Int) {}
473 
onPackageUninstallednull474     open fun MutateStateScope.onPackageUninstalled(packageName: String, appId: Int, userId: Int) {}
475 
onSystemReadynull476     open fun MutateStateScope.onSystemReady() {}
477 
migrateSystemStatenull478     open fun migrateSystemState(state: MutableAccessState) {}
479 
migrateUserStatenull480     open fun migrateUserState(state: MutableAccessState, userId: Int) {}
481 
upgradePackageStatenull482     open fun MutateStateScope.upgradePackageState(
483         packageState: PackageState,
484         userId: Int,
485         version: Int
486     ) {}
487 
parseSystemStatenull488     open fun BinaryXmlPullParser.parseSystemState(state: MutableAccessState) {}
489 
serializeSystemStatenull490     open fun BinaryXmlSerializer.serializeSystemState(state: AccessState) {}
491 
parseUserStatenull492     open fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {}
493 
serializeUserStatenull494     open fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {}
495 }
496