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

Commit 3482338b authored by Winson's avatar Winson
Browse files

Fix domain verify restore and add signature check

Verifies that all signatures of the package being restored matches by
SHA256 hash. And fixes a bug where the restored packages weren't being
added to the internal structures.

Bug: 170746586

Test: atest DomainVerificationPackageTest

Change-Id: I2cf2e739a88396475599bc4c1ff27c36e09a8d45
parent d65f0926
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -925,6 +925,11 @@ public class DomainVerificationService extends SystemService
            sendBroadcast = false;
        } else {
            pkgState = mSettings.removeRestoredState(pkgName);
            if (pkgState != null && !Objects.equals(pkgState.getBackupSignatureHash(),
                    PackageUtils.computeSignaturesSha256Digest(newPkgSetting.getSignatures()))) {
                // If restoring and the signatures don't match, drop the state
                pkgState = null;
            }
        }

        AndroidPackage pkg = newPkgSetting.getPkg();
+6 −2
Original line number Diff line number Diff line
@@ -157,16 +157,20 @@ class DomainVerificationSettings {
                    // mergePkgState runs, without the merge part.
                    ArrayMap<String, Integer> stateMap = newState.getStateMap();
                    int size = stateMap.size();
                    for (int index = 0; index < size; index++) {
                    for (int index = size - 1; index >= 0; index--) {
                        Integer stateInteger = stateMap.valueAt(index);
                        if (stateInteger != null) {
                            int state = stateInteger;
                            if (state == DomainVerificationState.STATE_SUCCESS
                                    || state == DomainVerificationState.STATE_RESTORED) {
                                stateMap.setValueAt(index, state);
                                stateMap.setValueAt(index, DomainVerificationState.STATE_RESTORED);
                            } else {
                                stateMap.removeAt(index);
                            }
                        }
                    }

                    mRestoredPkgStates.put(pkgName, newState);
                }
            }
        }
+123 −18
Original line number Diff line number Diff line
@@ -19,8 +19,10 @@ package com.android.server.pm.test.verify.domain
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.PackageUserState
import android.content.pm.Signature
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
import android.content.pm.verify.domain.DomainVerificationInfo.STATE_MODIFIABLE_VERIFIED
import android.content.pm.verify.domain.DomainVerificationInfo.STATE_NO_RESPONSE
import android.content.pm.verify.domain.DomainVerificationInfo.STATE_SUCCESS
import android.content.pm.verify.domain.DomainVerificationInfo.STATE_UNMODIFIABLE
@@ -42,7 +44,6 @@ import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.mockito.ArgumentMatchers
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
@@ -56,6 +57,10 @@ class DomainVerificationPackageTest {
        private const val PKG_TWO = "com.test.two"
        private val UUID_ONE = UUID.fromString("1b041c96-8d37-4932-a858-561bfac5947c")
        private val UUID_TWO = UUID.fromString("a3389c16-7f9f-4e86-85e3-500d1249c74c")
        private const val SIGNATURE_ONE = "AA"
        private const val DIGEST_ONE =
            "BCEEF655B5A034911F1C3718CE056531B45EF03B4C7B1F15629E867294011A7D"
        private const val SIGNATURE_TWO = "BB"

        private val DOMAIN_BASE = DomainVerificationPackageTest::class.java.packageName
        private val DOMAIN_1 = "one.$DOMAIN_BASE"
@@ -66,8 +71,8 @@ class DomainVerificationPackageTest {
        private const val USER_ID = 0
    }

    private val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE)
    private val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO)
    private val pkg1 = mockPkgSetting(PKG_ONE, UUID_ONE, SIGNATURE_ONE)
    private val pkg2 = mockPkgSetting(PKG_TWO, UUID_TWO, SIGNATURE_TWO)

    @Test
    fun addPackageFirstTime() {
@@ -95,6 +100,104 @@ class DomainVerificationPackageTest {
                .containsExactly(pkg1.getName())
    }

    @Test
    fun addPackageRestoredMatchingSignature() {
        // language=XML
        val xml = """
            <?xml?>
            <domain-verifications>
                <active>
                    <package-state
                        packageName="${pkg1.getName()}"
                        id="${pkg1.domainSetId}"
                        signature="$DIGEST_ONE"
                        >
                        <state>
                            <domain name="$DOMAIN_1" state="1"/>
                        </state>
                    </package-state>
                </active>
            </domain-verifications>
        """

        val service = makeService(pkg1, pkg2)
        service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream()))
        service.addPackage(pkg1)
        val info = service.getInfo(pkg1.getName())
        assertThat(info.packageName).isEqualTo(pkg1.getName())
        assertThat(info.identifier).isEqualTo(pkg1.domainSetId)
        assertThat(info.hostToStateMap).containsExactlyEntriesIn(
            mapOf(
                DOMAIN_1 to STATE_MODIFIABLE_VERIFIED,
                DOMAIN_2 to STATE_NO_RESPONSE,
            )
        )

        val userState = service.getUserState(pkg1.getName())
        assertThat(userState.packageName).isEqualTo(pkg1.getName())
        assertThat(userState.identifier).isEqualTo(pkg1.domainSetId)
        assertThat(userState.isLinkHandlingAllowed).isEqualTo(true)
        assertThat(userState.user.identifier).isEqualTo(USER_ID)
        assertThat(userState.hostToStateMap).containsExactlyEntriesIn(
            mapOf(
                DOMAIN_1 to DOMAIN_STATE_VERIFIED,
                DOMAIN_2 to DOMAIN_STATE_NONE,
            )
        )

        assertThat(service.queryValidVerificationPackageNames())
            .containsExactly(pkg1.getName())
    }

    @Test
    fun addPackageRestoredMismatchSignature() {
        // language=XML
        val xml = """
            <?xml?>
            <domain-verifications>
                <active>
                    <package-state
                        packageName="${pkg1.getName()}"
                        id="${pkg1.domainSetId}"
                        signature="INVALID_SIGNATURE"
                        >
                        <state>
                            <domain name="$DOMAIN_1" state="1"/>
                        </state>
                    </package-state>
                </active>
            </domain-verifications>
        """

        val service = makeService(pkg1, pkg2)
        service.restoreSettings(Xml.resolvePullParser(xml.byteInputStream()))
        service.addPackage(pkg1)
        val info = service.getInfo(pkg1.getName())
        assertThat(info.packageName).isEqualTo(pkg1.getName())
        assertThat(info.identifier).isEqualTo(pkg1.domainSetId)
        assertThat(info.hostToStateMap).containsExactlyEntriesIn(
            mapOf(
                DOMAIN_1 to STATE_NO_RESPONSE,
                DOMAIN_2 to STATE_NO_RESPONSE,
            )
        )

        val userState = service.getUserState(pkg1.getName())
        assertThat(userState.packageName).isEqualTo(pkg1.getName())
        assertThat(userState.identifier).isEqualTo(pkg1.domainSetId)
        assertThat(userState.isLinkHandlingAllowed).isEqualTo(true)
        assertThat(userState.user.identifier).isEqualTo(USER_ID)
        assertThat(userState.hostToStateMap).containsExactlyEntriesIn(
            mapOf(
                DOMAIN_1 to DOMAIN_STATE_NONE,
                DOMAIN_2 to DOMAIN_STATE_NONE,
            )
        )

        assertThat(service.queryValidVerificationPackageNames())
            .containsExactly(pkg1.getName())
    }

    @Test
    fun addPackageActive() {
        // language=XML
@@ -153,10 +256,9 @@ class DomainVerificationPackageTest {
    @Test
    fun migratePackageDropDomain() {
        val pkgName = PKG_ONE
        val pkgBefore = mockPkgSetting(pkgName, UUID_ONE,
        val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE,
            listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3, DOMAIN_4))
        val pkgAfter = mockPkgSetting(pkgName, UUID_TWO,
                listOf(DOMAIN_1, DOMAIN_2))
        val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO, listOf(DOMAIN_1, DOMAIN_2))

        // Test 4 domains:
        // 1 will be approved and preserved, 2 will be selected and preserved,
@@ -215,8 +317,8 @@ class DomainVerificationPackageTest {
    @Test
    fun migratePackageDropAll() {
        val pkgName = PKG_ONE
        val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, listOf(DOMAIN_1, DOMAIN_2))
        val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, emptyList())
        val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE, listOf(DOMAIN_1, DOMAIN_2))
        val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO, emptyList())

        val map = mutableMapOf<String, PackageSetting>()
        val service = makeService { map[it] }
@@ -257,9 +359,8 @@ class DomainVerificationPackageTest {
    @Test
    fun migratePackageAddDomain() {
        val pkgName = PKG_ONE
        val pkgBefore = mockPkgSetting(pkgName, UUID_ONE,
                listOf(DOMAIN_1, DOMAIN_2))
        val pkgAfter = mockPkgSetting(pkgName, UUID_TWO,
        val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE, listOf(DOMAIN_1, DOMAIN_2))
        val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO,
            listOf(DOMAIN_1, DOMAIN_2, DOMAIN_3))

        // Test 3 domains:
@@ -309,8 +410,8 @@ class DomainVerificationPackageTest {
    @Test
    fun migratePackageAddAll() {
        val pkgName = PKG_ONE
        val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, emptyList())
        val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, listOf(DOMAIN_1, DOMAIN_2))
        val pkgBefore = mockPkgSetting(pkgName, UUID_ONE, SIGNATURE_ONE, emptyList())
        val pkgAfter = mockPkgSetting(pkgName, UUID_TWO, SIGNATURE_TWO, listOf(DOMAIN_1, DOMAIN_2))

        val map = mutableMapOf<String, PackageSetting>()
        val service = makeService { map[it] }
@@ -387,9 +488,12 @@ class DomainVerificationPackageTest {
                })
            }

    private fun mockPkgSetting(pkgName: String, domainSetId: UUID, domains: List<String> = listOf(
            DOMAIN_1, DOMAIN_2
    )) = mockThrowOnUnmocked<PackageSetting> {
    private fun mockPkgSetting(
        pkgName: String,
        domainSetId: UUID,
        signature: String,
        domains: List<String> = listOf(DOMAIN_1, DOMAIN_2)
    ) = mockThrowOnUnmocked<PackageSetting> {
        val pkg = mockThrowOnUnmocked<AndroidPackage> {
            whenever(packageName) { pkgName }
            whenever(targetSdkVersion) { Build.VERSION_CODES.S }
@@ -423,5 +527,6 @@ class DomainVerificationPackageTest {
        whenever(getInstantApp(anyInt())) { false }
        whenever(firstInstallTime) { 0L }
        whenever(readUserState(USER_ID)) { PackageUserState() }
        whenever(signatures) { arrayOf(Signature(signature)) }
    }
}