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.pm.test.verify.domain 18 19 import android.content.Context 20 import android.content.Intent 21 import android.content.pm.PackageManager 22 import android.content.pm.SigningDetails 23 import android.content.pm.verify.domain.DomainVerificationManager 24 import android.content.pm.verify.domain.DomainVerificationState 25 import android.os.Build 26 import android.os.Process 27 import android.util.ArraySet 28 import android.util.IndentingPrintWriter 29 import android.util.SparseArray 30 import androidx.test.platform.app.InstrumentationRegistry 31 import com.android.server.pm.Computer 32 import com.android.server.pm.parsing.pkg.AndroidPackageInternal 33 import com.android.server.pm.pkg.AndroidPackage 34 import com.android.server.pm.pkg.PackageStateInternal 35 import com.android.server.pm.pkg.PackageUserStateInternal 36 import com.android.server.pm.pkg.component.ParsedActivityImpl 37 import com.android.server.pm.pkg.component.ParsedIntentInfoImpl 38 import com.android.server.pm.verify.domain.DomainVerificationEnforcer 39 import com.android.server.pm.verify.domain.DomainVerificationManagerInternal 40 import com.android.server.pm.verify.domain.DomainVerificationService 41 import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy 42 import com.android.server.testutils.mockThrowOnUnmocked 43 import com.android.server.testutils.whenever 44 import org.junit.Test 45 import org.junit.runner.RunWith 46 import org.junit.runners.Parameterized 47 import org.mockito.Mockito.any 48 import org.mockito.Mockito.anyInt 49 import org.mockito.Mockito.anyLong 50 import org.mockito.Mockito.anyString 51 import org.mockito.Mockito.eq 52 import org.mockito.Mockito.mock 53 import org.mockito.Mockito.verifyNoMoreInteractions 54 import java.util.UUID 55 import java.util.concurrent.atomic.AtomicBoolean 56 import java.util.concurrent.atomic.AtomicInteger 57 import kotlin.test.assertFailsWith 58 import kotlin.test.fail 59 60 @RunWith(Parameterized::class) 61 class DomainVerificationEnforcerTest { 62 63 val context: Context = InstrumentationRegistry.getInstrumentation().context 64 65 companion object { 66 private val INTERNAL_UIDS = listOf(Process.ROOT_UID, Process.SHELL_UID, Process.SYSTEM_UID) 67 private const val VERIFIER_UID = Process.FIRST_APPLICATION_UID + 1 68 private const val NON_VERIFIER_UID = Process.FIRST_APPLICATION_UID + 2 69 70 private const val VISIBLE_PKG = "com.test.visible" 71 private val VISIBLE_UUID = UUID.fromString("8db01272-270d-4606-a3db-bb35228ff9a2") 72 private const val INVISIBLE_PKG = "com.test.invisible" 73 private val INVISIBLE_UUID = UUID.fromString("16dcb029-d96c-4a19-833a-4c9d72e2ebc3") 74 75 @JvmStatic 76 @Parameterized.Parameters(name = "{0}") 77 fun parameters(): Array<Any> { 78 val visiblePkg = mockPkg(VISIBLE_PKG) 79 val visiblePkgState = mockPkgState(VISIBLE_PKG, VISIBLE_UUID) 80 val invisiblePkg = mockPkg(INVISIBLE_PKG) 81 val invisiblePkgState = mockPkgState(INVISIBLE_PKG, INVISIBLE_UUID) 82 83 val makeEnforcer: (Context) -> DomainVerificationEnforcer = { 84 DomainVerificationEnforcer(it).apply { 85 setCallback(mockThrowOnUnmocked { 86 whenever(filterAppAccess(eq(VISIBLE_PKG), anyInt(), anyInt())) { false } 87 whenever(filterAppAccess(eq(INVISIBLE_PKG), anyInt(), anyInt())) { 88 true 89 } 90 whenever(doesUserExist(anyInt())) { (arguments[0] as Int) <= 1 } 91 }) 92 } 93 } 94 95 val makeService: (Context) -> Triple<AtomicInteger, AtomicInteger, 96 DomainVerificationService> = { 97 val callingUidInt = AtomicInteger(-1) 98 val callingUserIdInt = AtomicInteger(-1) 99 100 val connection: DomainVerificationManagerInternal.Connection = 101 mockThrowOnUnmocked { 102 whenever(callingUid) { callingUidInt.get() } 103 whenever(callingUserId) { callingUserIdInt.get() } 104 whenever(snapshot()) { 105 mockThrowOnUnmocked { 106 whenever(getPackageStateInternal(anyString())) { 107 when (getArgument<String>(0)) { 108 VISIBLE_PKG -> visiblePkgState 109 INVISIBLE_PKG -> invisiblePkgState 110 else -> null 111 } 112 } 113 } 114 } 115 whenever(schedule(anyInt(), any())) 116 whenever(scheduleWriteSettings()) 117 whenever(filterAppAccess(eq(VISIBLE_PKG), anyInt(), anyInt())) { false } 118 whenever(filterAppAccess(eq(INVISIBLE_PKG), anyInt(), anyInt())) { 119 true 120 } 121 whenever(doesUserExist(anyInt())) { (arguments[0] as Int) <= 1 } 122 } 123 val service = DomainVerificationService( 124 it, 125 mockThrowOnUnmocked { whenever(linkedApps) { ArraySet<String>() } }, 126 mockThrowOnUnmocked { 127 whenever(isChangeEnabledInternalNoLogging(anyLong(), any())) { true } 128 }).apply { 129 setConnection(connection) 130 } 131 132 Triple(callingUidInt, callingUserIdInt, service) 133 } 134 135 fun enforcer( 136 type: Type, 137 name: String, 138 block: DomainVerificationEnforcer.(Params.Input<DomainVerificationEnforcer>) -> Any? 139 ) = Params(type, makeEnforcer, name) { 140 it.target.block(it) 141 } 142 143 fun service( 144 type: Type, 145 name: String, 146 block: DomainVerificationService.(Params.Input<Triple<AtomicInteger, AtomicInteger, DomainVerificationService>>) -> Any? 147 ) = Params(type, makeService, name) { 148 val (callingUidInt, callingUserIdInt, service) = it.target 149 callingUidInt.set(it.callingUid) 150 callingUserIdInt.set(it.callingUserId) 151 service.proxy = it.proxy 152 service.addPackage(visiblePkgState) 153 service.addPackage(invisiblePkgState) 154 service.block(it) 155 } 156 157 return arrayOf( 158 enforcer(Type.INTERNAL, "internal") { 159 assertInternal(it.callingUid) 160 }, 161 enforcer(Type.QUERENT, "approvedQuerent") { 162 assertApprovedQuerent(it.callingUid, it.proxy) 163 }, 164 enforcer(Type.VERIFIER, "approvedVerifier") { 165 assertApprovedVerifier(it.callingUid, it.proxy) 166 }, 167 enforcer( 168 Type.SELECTION_QUERENT, 169 "approvedUserStateQuerent" 170 ) { 171 assertApprovedUserStateQuerent( 172 it.callingUid, it.callingUserId, 173 it.targetPackageName, it.userId 174 ) 175 }, 176 enforcer( 177 Type.SELECTOR, 178 "approvedUserSelector" 179 ) { 180 assertApprovedUserSelector( 181 it.callingUid, it.callingUserId, 182 it.targetPackageName, it.userId 183 ) 184 }, 185 service(Type.INTERNAL, "setStatusInternalPackageName") { 186 setDomainVerificationStatusInternal( 187 it.targetPackageName, 188 DomainVerificationState.STATE_SUCCESS, 189 ArraySet(setOf("example.com")) 190 ) 191 }, 192 service(Type.INTERNAL, "setUserStateInternal") { 193 setDomainVerificationUserSelectionInternal( 194 it.userId, 195 it.targetPackageName, 196 false, 197 ArraySet(setOf("example.com")) 198 ) 199 }, 200 service(Type.INTERNAL, "verifyPackages") { 201 verifyPackages(listOf(it.targetPackageName), true) 202 }, 203 service(Type.INTERNAL, "clearState") { 204 clearDomainVerificationState(listOf(it.targetPackageName)) 205 }, 206 service(Type.INTERNAL, "clearUserStates") { 207 clearUserStates(listOf(it.targetPackageName), it.userId) 208 }, 209 service(Type.VERIFIER, "queryValidPackageNames") { 210 queryValidVerificationPackageNames() 211 }, 212 service(Type.QUERENT, "getInfo") { 213 getDomainVerificationInfo(it.targetPackageName) 214 }, 215 service(Type.QUERENT, "printState") { 216 printState(mock(IndentingPrintWriter::class.java), null, null) 217 }, 218 service(Type.QUERENT, "printStateInternal") { 219 printState(mock(Computer::class.java), mock(IndentingPrintWriter::class.java), 220 null, null) 221 }, 222 service(Type.QUERENT, "printOwnersForPackage") { 223 printOwnersForPackage( 224 mock(IndentingPrintWriter::class.java), 225 it.targetPackageName, 226 it.userId 227 ) 228 }, 229 service(Type.QUERENT, "printOwnersForDomains") { 230 printOwnersForDomains( 231 mock(IndentingPrintWriter::class.java), 232 listOf("example.com"), 233 it.userId 234 ) 235 }, 236 service(Type.VERIFIER, "setStatus") { 237 setDomainVerificationStatus( 238 it.targetDomainSetId, 239 setOf("example.com"), 240 DomainVerificationState.STATE_SUCCESS 241 ) 242 }, 243 service(Type.VERIFIER, "setStatusInternalUid") { 244 setDomainVerificationStatusInternal( 245 it.callingUid, 246 it.targetDomainSetId, 247 setOf("example.com"), 248 DomainVerificationState.STATE_SUCCESS 249 ) 250 }, 251 service(Type.SELECTOR_USER, "setLinkHandlingAllowedUserId") { 252 setDomainVerificationLinkHandlingAllowed(it.targetPackageName, true, it.userId) 253 }, 254 service(Type.SELECTION_QUERENT, "getUserStateUserId") { 255 getDomainVerificationUserState(it.targetPackageName, it.userId) 256 }, 257 service(Type.SELECTOR_USER, "setUserStateUserId") { 258 setDomainVerificationUserSelection( 259 it.targetDomainSetId, 260 setOf("example.com"), 261 true, 262 it.userId 263 ) 264 }, 265 service(Type.LEGACY_SELECTOR, "setLegacyUserState") { 266 setLegacyUserState( 267 it.targetPackageName, it.userId, 268 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER 269 ) 270 }, 271 service(Type.LEGACY_QUERENT, "getLegacyUserState") { 272 getLegacyState(it.targetPackageName, it.userId) 273 }, 274 service(Type.OWNER_QUERENT_USER, "getOwnersForDomainUserId") { 275 // Re-use package name, since the result itself isn't relevant 276 getOwnersForDomain(it.targetPackageName, it.userId) 277 }, 278 ) 279 } 280 281 data class Params<T : Any>( 282 val type: Type, 283 val construct: (context: Context) -> T, 284 val name: String, 285 private val method: (Input<T>) -> Any? 286 ) { 287 override fun toString() = "${type}_$name" 288 289 fun runMethod( 290 target: Any, 291 callingUid: Int, 292 callingUserId: Int, 293 userId: Int, 294 targetPackageName: String, 295 targetDomainSetId: UUID, 296 proxy: DomainVerificationProxy 297 ): Any? = method( 298 Input( 299 @Suppress("UNCHECKED_CAST") 300 target as T, 301 callingUid, 302 callingUserId, 303 userId, 304 targetPackageName, 305 targetDomainSetId, 306 proxy 307 ) 308 ) 309 310 data class Input<T>( 311 val target: T, 312 val callingUid: Int, 313 val callingUserId: Int, 314 val userId: Int, 315 val targetPackageName: String, 316 val targetDomainSetId: UUID, 317 val proxy: DomainVerificationProxy 318 ) 319 } 320 321 fun mockPkg(packageName: String) = mockThrowOnUnmocked<AndroidPackageInternal> { 322 whenever(this.packageName) { packageName } 323 whenever(targetSdkVersion) { Build.VERSION_CODES.S } 324 whenever(isEnabled) { true } 325 whenever(activities) { 326 listOf( 327 ParsedActivityImpl().apply { 328 addIntent( 329 ParsedIntentInfoImpl() 330 .apply { 331 intentFilter.apply { 332 autoVerify = true 333 addAction(Intent.ACTION_VIEW) 334 addCategory(Intent.CATEGORY_BROWSABLE) 335 addCategory(Intent.CATEGORY_DEFAULT) 336 addDataScheme("https") 337 addDataAuthority("example.com", null) 338 } 339 } 340 ) 341 } 342 ) 343 } 344 whenever(signingDetails) { SigningDetails.UNKNOWN } 345 } 346 347 fun mockPkgState(packageName: String, domainSetId: UUID) = 348 mockThrowOnUnmocked<PackageStateInternal> { 349 whenever(this.packageName) { packageName } 350 whenever(pkg) { mockPkg(packageName) } 351 whenever(this.domainSetId) { domainSetId } 352 whenever(getUserStateOrDefault(0)) { PackageUserStateInternal.DEFAULT } 353 whenever(getUserStateOrDefault(1)) { PackageUserStateInternal.DEFAULT } 354 whenever(userStates) { 355 SparseArray<PackageUserStateInternal>().apply { 356 this[0] = PackageUserStateInternal.DEFAULT 357 this[1] = PackageUserStateInternal.DEFAULT 358 } 359 } 360 whenever(isSystem) { false } 361 whenever(signingDetails) { SigningDetails.UNKNOWN } 362 } 363 } 364 365 @Parameterized.Parameter(0) 366 lateinit var params: Params<*> 367 368 private val proxy: DomainVerificationProxy = mockThrowOnUnmocked { 369 whenever(isCallerVerifier(VERIFIER_UID)) { true } 370 whenever(isCallerVerifier(NON_VERIFIER_UID)) { false } 371 whenever(sendBroadcastForPackages(any())) 372 } 373 374 @Test 375 fun verify() { 376 when (params.type) { 377 Type.INTERNAL -> internal() 378 Type.QUERENT -> approvedQuerent() 379 Type.VERIFIER -> approvedVerifier() 380 Type.SELECTION_QUERENT -> approvedUserStateQuerent(verifyCrossUser = true) 381 Type.SELECTOR -> approvedUserSelector(verifyCrossUser = false) 382 Type.SELECTOR_USER -> approvedUserSelector(verifyCrossUser = true) 383 Type.LEGACY_QUERENT -> legacyQuerent() 384 Type.LEGACY_SELECTOR -> legacyUserSelector() 385 Type.OWNER_QUERENT -> ownerQuerent(verifyCrossUser = false) 386 Type.OWNER_QUERENT_USER -> ownerQuerent(verifyCrossUser = true) 387 }.run { /*exhaust*/ } 388 } 389 390 private fun internal() { 391 val context: Context = mockThrowOnUnmocked() 392 val target = params.construct(context) 393 394 // Internal doesn't care about visibility 395 listOf(true, false).forEach { visible -> 396 INTERNAL_UIDS.forEach { runMethod(target, it, visible) } 397 assertFails { runMethod(target, VERIFIER_UID, visible) } 398 assertFails { 399 runMethod(target, NON_VERIFIER_UID, visible) 400 } 401 } 402 } 403 404 private fun approvedQuerent() { 405 val allowUserState = AtomicBoolean(false) 406 val allowPreferredApps = AtomicBoolean(false) 407 val allowQueryAll = AtomicBoolean(false) 408 val allowDump = AtomicBoolean(false) 409 val context: Context = mockThrowOnUnmocked { 410 initPermission( 411 allowUserState, 412 android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION 413 ) 414 initPermission( 415 allowPreferredApps, 416 android.Manifest.permission.SET_PREFERRED_APPLICATIONS 417 ) 418 initPermission(allowQueryAll, android.Manifest.permission.QUERY_ALL_PACKAGES) 419 initPermission(allowDump, android.Manifest.permission.DUMP) 420 } 421 val target = params.construct(context) 422 423 INTERNAL_UIDS.forEach { runMethod(target, it) } 424 425 verifyNoMoreInteractions(context) 426 427 assertFails { runMethod(target, VERIFIER_UID) } 428 assertFails { runMethod(target, NON_VERIFIER_UID) } 429 430 // Check that the verifier only needs QUERY_ALL to pass 431 allowQueryAll.set(true) 432 runMethod(target, VERIFIER_UID) 433 allowQueryAll.set(false) 434 435 allowPreferredApps.set(true) 436 437 assertFails { runMethod(target, NON_VERIFIER_UID) } 438 439 allowUserState.set(true) 440 441 assertFails { runMethod(target, NON_VERIFIER_UID) } 442 443 allowQueryAll.set(true) 444 445 assertFails { runMethod(target, NON_VERIFIER_UID) } 446 447 allowDump.set(true) 448 449 runMethod(target, NON_VERIFIER_UID) 450 } 451 452 private fun approvedVerifier() { 453 val allowDomainVerificationAgent = AtomicBoolean(false) 454 val allowIntentVerificationAgent = AtomicBoolean(false) 455 val allowQueryAll = AtomicBoolean(false) 456 val context: Context = mockThrowOnUnmocked { 457 initPermission( 458 allowDomainVerificationAgent, 459 android.Manifest.permission.DOMAIN_VERIFICATION_AGENT 460 ) 461 initPermission( 462 allowIntentVerificationAgent, 463 android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT 464 ) 465 initPermission(allowQueryAll, android.Manifest.permission.QUERY_ALL_PACKAGES) 466 } 467 val target = params.construct(context) 468 469 INTERNAL_UIDS.forEach { runMethod(target, it) } 470 471 verifyNoMoreInteractions(context) 472 473 assertFails { runMethod(target, VERIFIER_UID) } 474 assertFails { runMethod(target, NON_VERIFIER_UID) } 475 476 allowDomainVerificationAgent.set(true) 477 478 assertFails { runMethod(target, VERIFIER_UID) } 479 assertFails { runMethod(target, NON_VERIFIER_UID) } 480 481 allowQueryAll.set(true) 482 483 runMethod(target, VERIFIER_UID) 484 assertFails { runMethod(target, NON_VERIFIER_UID) } 485 486 // Check that v1 verifiers are also allowed through 487 allowDomainVerificationAgent.set(false) 488 allowIntentVerificationAgent.set(true) 489 490 runMethod(target, VERIFIER_UID) 491 assertFails { runMethod(target, NON_VERIFIER_UID) } 492 } 493 494 private fun approvedUserStateQuerent(verifyCrossUser: Boolean) { 495 val allowInteractAcrossUsers = AtomicBoolean(false) 496 val context: Context = mockThrowOnUnmocked { 497 initPermission( 498 allowInteractAcrossUsers, 499 android.Manifest.permission.INTERACT_ACROSS_USERS 500 ) 501 } 502 val target = params.construct(context) 503 504 fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) { 505 // User selector makes no distinction by UID 506 val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID 507 runCrossUserMethod(allUids, target, callingUserId, targetUserId, throws) 508 } 509 510 val callingUserId = 0 511 val notCallingUserId = 1 512 513 runTestCases(callingUserId, callingUserId, throws = false) 514 if (verifyCrossUser) { 515 runTestCases(callingUserId, notCallingUserId, throws = true) 516 } 517 518 allowInteractAcrossUsers.set(true) 519 520 runTestCases(callingUserId, callingUserId, throws = false) 521 if (verifyCrossUser) { 522 runTestCases(callingUserId, notCallingUserId, throws = false) 523 } 524 } 525 526 private fun approvedUserSelector(verifyCrossUser: Boolean) { 527 val allowUserState = AtomicBoolean(false) 528 val allowInteractAcrossUsers = AtomicBoolean(false) 529 val context: Context = mockThrowOnUnmocked { 530 initPermission( 531 allowUserState, 532 android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION 533 ) 534 initPermission( 535 allowInteractAcrossUsers, 536 android.Manifest.permission.INTERACT_ACROSS_USERS 537 ) 538 } 539 val target = params.construct(context) 540 541 fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) { 542 // User selector makes no distinction by UID 543 val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID 544 runCrossUserMethod(allUids, target, callingUserId, targetUserId, throws) 545 } 546 547 val callingUserId = 0 548 val notCallingUserId = 1 549 550 runTestCases(callingUserId, callingUserId, throws = true) 551 if (verifyCrossUser) { 552 runTestCases(callingUserId, notCallingUserId, throws = true) 553 } 554 555 allowUserState.set(true) 556 557 runTestCases(callingUserId, callingUserId, throws = false) 558 if (verifyCrossUser) { 559 runTestCases(callingUserId, notCallingUserId, throws = true) 560 } 561 562 allowInteractAcrossUsers.set(true) 563 564 runTestCases(callingUserId, callingUserId, throws = false) 565 if (verifyCrossUser) { 566 runTestCases(callingUserId, notCallingUserId, throws = false) 567 } 568 } 569 570 private fun legacyUserSelector() { 571 val allowInteractAcrossUsers = AtomicBoolean(false) 572 val allowPreferredApps = AtomicBoolean(false) 573 val context: Context = mockThrowOnUnmocked { 574 initPermission( 575 allowInteractAcrossUsers, 576 android.Manifest.permission.INTERACT_ACROSS_USERS 577 ) 578 initPermission( 579 allowPreferredApps, 580 android.Manifest.permission.SET_PREFERRED_APPLICATIONS 581 ) 582 } 583 val target = params.construct(context) 584 585 fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) { 586 // Legacy makes no distinction by UID 587 val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID 588 // The legacy selector does a silent failure when the user IDs don't match, so it 589 // cannot verify the non-existent user ID check, as it will not throw an Exception. 590 runCrossUserMethod(allUids, target, callingUserId, targetUserId, throws, 591 verifyUserIdCheck = false) 592 } 593 594 val callingUserId = 0 595 val notCallingUserId = 1 596 597 runTestCases(callingUserId, callingUserId, throws = true) 598 runTestCases(callingUserId, notCallingUserId, throws = true) 599 600 allowPreferredApps.set(true) 601 602 runTestCases(callingUserId, callingUserId, throws = false) 603 runTestCases(callingUserId, notCallingUserId, throws = true) 604 605 allowInteractAcrossUsers.set(true) 606 607 runTestCases(callingUserId, callingUserId, throws = false) 608 runTestCases(callingUserId, notCallingUserId, throws = false) 609 } 610 611 private fun legacyQuerent() { 612 val allowInteractAcrossUsers = AtomicBoolean(false) 613 val allowInteractAcrossUsersFull = AtomicBoolean(false) 614 val context: Context = mockThrowOnUnmocked { 615 initPermission( 616 allowInteractAcrossUsers, 617 android.Manifest.permission.INTERACT_ACROSS_USERS 618 ) 619 initPermission( 620 allowInteractAcrossUsersFull, 621 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL 622 ) 623 } 624 val target = params.construct(context) 625 626 // Legacy code can return PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED 627 // as an error code. This is distinct from the class level assertFails as unfortunately 628 // the same number, 0, is used in opposite contexts, where it does represent a failure 629 // for this legacy case, but not for the modern APIs. 630 fun assertFailsLegacy(block: () -> Any?) { 631 try { 632 val value = block() 633 if ((value as? Int) 634 != PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED 635 ) { 636 throw AssertionError("Expected call to return false, was $value") 637 } 638 } catch (e: SecurityException) { 639 } catch (e: PackageManager.NameNotFoundException) { 640 // Any of these 2 exceptions are considered failures, which is expected 641 } 642 } 643 644 fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) { 645 // Legacy makes no distinction by UID 646 val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID 647 runCrossUserMethod(allUids, target, callingUserId, targetUserId, throws, 648 assertFailsMethod = ::assertFailsLegacy) 649 } 650 651 val callingUserId = 0 652 val notCallingUserId = 1 653 654 runTestCases(callingUserId, callingUserId, throws = false) 655 runTestCases(callingUserId, notCallingUserId, throws = true) 656 657 // Legacy requires the _FULL permission, so this should continue to fail 658 allowInteractAcrossUsers.set(true) 659 runTestCases(callingUserId, callingUserId, throws = false) 660 runTestCases(callingUserId, notCallingUserId, throws = true) 661 662 allowInteractAcrossUsersFull.set(true) 663 runTestCases(callingUserId, callingUserId, throws = false) 664 runTestCases(callingUserId, notCallingUserId, throws = false) 665 } 666 667 private fun ownerQuerent(verifyCrossUser: Boolean) { 668 val allowQueryAll = AtomicBoolean(false) 669 val allowUserState = AtomicBoolean(false) 670 val allowInteractAcrossUsers = AtomicBoolean(false) 671 val context: Context = mockThrowOnUnmocked { 672 initPermission( 673 allowQueryAll, 674 android.Manifest.permission.QUERY_ALL_PACKAGES 675 ) 676 initPermission( 677 allowUserState, 678 android.Manifest.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION 679 ) 680 initPermission( 681 allowInteractAcrossUsers, 682 android.Manifest.permission.INTERACT_ACROSS_USERS 683 ) 684 } 685 val target = params.construct(context) 686 687 fun runTestCases(callingUserId: Int, targetUserId: Int, throws: Boolean) { 688 // Owner querent makes no distinction by UID 689 val allUids = INTERNAL_UIDS + VERIFIER_UID + NON_VERIFIER_UID 690 runCrossUserMethod(allUids, target, callingUserId, targetUserId, throws, 691 verifyInvisiblePkg = false) 692 } 693 694 val callingUserId = 0 695 val notCallingUserId = 1 696 697 runTestCases(callingUserId, callingUserId, throws = true) 698 if (verifyCrossUser) { 699 runTestCases(callingUserId, notCallingUserId, throws = true) 700 } 701 702 allowQueryAll.set(true) 703 704 runTestCases(callingUserId, callingUserId, throws = true) 705 if (verifyCrossUser) { 706 runTestCases(callingUserId, notCallingUserId, throws = true) 707 } 708 709 allowUserState.set(true) 710 711 runTestCases(callingUserId, callingUserId, throws = false) 712 if (verifyCrossUser) { 713 runTestCases(callingUserId, notCallingUserId, throws = true) 714 } 715 716 allowQueryAll.set(false) 717 718 runTestCases(callingUserId, callingUserId, throws = true) 719 if (verifyCrossUser) { 720 runTestCases(callingUserId, notCallingUserId, throws = true) 721 } 722 723 allowQueryAll.set(true) 724 allowInteractAcrossUsers.set(true) 725 726 runTestCases(callingUserId, callingUserId, throws = false) 727 if (verifyCrossUser) { 728 runTestCases(callingUserId, notCallingUserId, throws = false) 729 } 730 } 731 732 private fun Context.initPermission(boolean: AtomicBoolean, permission: String) { 733 whenever(enforcePermission(eq(permission), anyInt(), anyInt(), anyString())) { 734 if (!boolean.get()) { 735 throw SecurityException() 736 } 737 } 738 whenever(checkPermission(eq(permission), anyInt(), anyInt())) { 739 if (boolean.get()) { 740 PackageManager.PERMISSION_GRANTED 741 } else { 742 PackageManager.PERMISSION_DENIED 743 } 744 } 745 } 746 747 private fun runMethod( 748 target: Any, 749 callingUid: Int, 750 visible: Boolean = true, 751 callingUserId: Int = 0, 752 userId: Int = 0 753 ): Any? { 754 val packageName = if (visible) VISIBLE_PKG else INVISIBLE_PKG 755 val uuid = if (visible) VISIBLE_UUID else INVISIBLE_UUID 756 return params.runMethod(target, callingUid, callingUserId, userId, packageName, uuid, proxy) 757 } 758 759 private fun runCrossUserMethod( 760 allUids: Iterable<Int>, 761 target: Any, 762 callingUserId: Int, 763 targetUserId: Int, 764 throws: Boolean, 765 verifyUserIdCheck: Boolean = true, 766 verifyInvisiblePkg: Boolean = true, 767 assertFailsMethod: (() -> Any?) -> Unit = ::assertFails, 768 ) { 769 if (throws) { 770 allUids.forEach { 771 assertFailsMethod { 772 // When testing a non-user ID failure, send an invalid user ID. 773 // This ensures the failure occurs before the user ID check is run. 774 try { 775 runMethod(target, it, visible = true, callingUserId, 100) 776 } catch (e: SecurityException) { 777 if (verifyUserIdCheck) { 778 e.message?.let { 779 if (it.contains("user ID", ignoreCase = true) 780 || it.contains("100")) { 781 fail( 782 "Method should not check user existence before permissions" 783 ) 784 } 785 } 786 } 787 788 // Rethrow to allow normal fail checking logic to run 789 throw e 790 } 791 } 792 } 793 } else { 794 allUids.forEach { 795 runMethod(target, it, visible = true, callingUserId, targetUserId) 796 } 797 } 798 799 if (verifyInvisiblePkg) { 800 allUids.forEach { 801 assertFailsMethod { 802 runMethod(target, it, visible = false, callingUserId, targetUserId) 803 } 804 } 805 } 806 807 if (verifyUserIdCheck) { 808 // An invalid target user ID should always fail 809 allUids.forEach { 810 assertFailsWith(SecurityException::class) { 811 runMethod(target, it, visible = true, callingUserId, 100) 812 } 813 } 814 815 // An invalid calling user ID should always fail, although this cannot happen in prod 816 allUids.forEach { 817 assertFailsWith(SecurityException::class) { 818 runMethod(target, it, visible = true, 100, targetUserId) 819 } 820 } 821 } 822 } 823 824 private fun assertFails(block: () -> Any?) { 825 try { 826 val value = block() 827 // Some methods return false or an error rather than throwing, so check that as well 828 val valueAsBoolean = value as? Boolean 829 if (valueAsBoolean == false) { 830 // Expected failure, do not throw 831 return 832 } 833 834 val valueAsInt = value as? Int 835 if (valueAsInt != null) { 836 if (valueAsInt == DomainVerificationManager.STATUS_OK) { 837 throw AssertionError("Expected call to return false, was $value") 838 } 839 } else { 840 throw AssertionError("Expected call to fail") 841 } 842 } catch (e: SecurityException) { 843 } catch (e: PackageManager.NameNotFoundException) { 844 // Any of these 2 exceptions are considered failures, which is expected 845 } 846 } 847 848 enum class Type { 849 // System/shell only 850 INTERNAL, 851 852 // INTERNAL || non-legacy domain verification agent || DUMP permission 853 QUERENT, 854 855 // INTERNAL || domain verification agent 856 VERIFIER, 857 858 // No permissions, allows all apps to view domain state for visible packages 859 SELECTION_QUERENT, 860 861 // Holding the user setting permission 862 SELECTOR, 863 864 // Holding the user setting permission, but targeting cross user 865 SELECTOR_USER, 866 867 // Legacy required no permissions except when cross-user 868 LEGACY_QUERENT, 869 870 // Holding the legacy preferred apps permission 871 LEGACY_SELECTOR, 872 873 // Holding user setting permission, but not targeting a package 874 OWNER_QUERENT, 875 876 // Holding user setting permission, but not targeting a package, but targeting cross user 877 OWNER_QUERENT_USER, 878 } 879 } 880