From dec5b1985f6930856c6fde0be2e9ef47623c7306 Mon Sep 17 00:00:00 2001 From: Winson Date: Tue, 16 Nov 2021 11:00:06 -0800 Subject: [PATCH] Verify PackageManagerShellCommand caller is shell Also verifies that printing domain verification state asserts that the caller is an approved querent, to match the getDomainVerificationInfo Java API. Bug: 200035185 Test: atest DomainVerificationEnforcerTest Change-Id: I1daeeee9d44e54e21643fe6253ff8012dbe364b8 --- .../server/pm/PackageManagerShellCommand.java | 15 +++++++++++++ .../domain/DomainVerificationService.java | 1 + .../domain/DomainVerificationEnforcerTest.kt | 21 +++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 0564e858c84c5..fdcf1fcfd260c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -18,6 +18,7 @@ package com.android.server.pm; import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; +import android.Manifest; import android.accounts.IAccountManager; import android.annotation.NonNull; import android.annotation.UserIdInt; @@ -170,6 +171,20 @@ class PackageManagerShellCommand extends ShellCommand { @Override public int onCommand(String cmd) { + switch (Binder.getCallingUid()) { + case Process.ROOT_UID: + case Process.SHELL_UID: + break; + default: + // This is called from a test and is allowed as non-shell with the right permission + if ("install-incremental".equals(cmd)) { + mContext.enforceCallingPermission(Manifest.permission.USE_SYSTEM_DATA_LOADERS, + "Caller missing USE_SYSTEM_DATA_LOADERS permission to use " + cmd); + } else { + throw new IllegalArgumentException("Caller must be root or shell"); + } + } + if (cmd == null) { return handleDefaultCommands(cmd); } diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java index 661e67d424aea..970d6d31127f6 100644 --- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java +++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java @@ -1197,6 +1197,7 @@ public class DomainVerificationService extends SystemService @Nullable @UserIdInt Integer userId, @NonNull Function pkgSettingFunction) throws NameNotFoundException { + mEnforcer.assertApprovedQuerent(mConnection.getCallingUid(), mProxy); synchronized (mLock) { mDebug.printState(writer, packageName, userId, pkgSettingFunction, mAttachedPkgStates); } diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt index d1d7cc6422c33..d9dbf48f969fe 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt @@ -19,6 +19,7 @@ package com.android.server.pm.test.verify.domain import android.content.Context import android.content.Intent import android.content.pm.PackageManager +import android.content.pm.SigningDetails import android.content.pm.parsing.component.ParsedActivityImpl import android.content.pm.parsing.component.ParsedIntentInfoImpl import android.content.pm.verify.domain.DomainVerificationManager @@ -26,6 +27,7 @@ import android.content.pm.verify.domain.DomainVerificationState import android.os.Build import android.os.Process import android.util.ArraySet +import android.util.IndentingPrintWriter import android.util.SparseArray import androidx.test.platform.app.InstrumentationRegistry import com.android.server.pm.parsing.pkg.AndroidPackage @@ -46,6 +48,7 @@ import org.mockito.Mockito.anyInt import org.mockito.Mockito.anyLong import org.mockito.Mockito.anyString import org.mockito.Mockito.eq +import org.mockito.Mockito.mock import org.mockito.Mockito.verifyNoMoreInteractions import java.util.UUID import java.util.concurrent.atomic.AtomicBoolean @@ -204,6 +207,14 @@ class DomainVerificationEnforcerTest { service(Type.QUERENT, "getInfo") { getDomainVerificationInfo(it.targetPackageName) }, + service(Type.QUERENT, "printState") { + printState(mock(IndentingPrintWriter::class.java), null, null) + }, + service(Type.QUERENT, "printStateInternal") { + printState(mock(IndentingPrintWriter::class.java), null, null) { + mockPkgState(it, UUID.randomUUID()) + } + }, service(Type.VERIFIER, "setStatus") { setDomainVerificationStatus( it.targetDomainSetId, @@ -311,6 +322,7 @@ class DomainVerificationEnforcerTest { } ) } + whenever(signingDetails) { SigningDetails.UNKNOWN } } fun mockPkgState(packageName: String, domainSetId: UUID) = @@ -327,6 +339,7 @@ class DomainVerificationEnforcerTest { } } whenever(isSystem) { false } + whenever(signingDetails) { SigningDetails.UNKNOWN } } } @@ -794,8 +807,12 @@ class DomainVerificationEnforcerTest { } val valueAsInt = value as? Int - if (valueAsInt != null && valueAsInt == DomainVerificationManager.STATUS_OK) { - throw AssertionError("Expected call to return false, was $value") + if (valueAsInt != null) { + if (valueAsInt == DomainVerificationManager.STATUS_OK) { + throw AssertionError("Expected call to return false, was $value") + } + } else { + throw AssertionError("Expected call to fail") } } catch (e: SecurityException) { } catch (e: PackageManager.NameNotFoundException) {