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

Commit db0a1f00 authored by Song Chun Fan's avatar Song Chun Fan Committed by Android (Google) Code Review
Browse files

Merge "[ADI][60/N] Update emergency-bypass conditions" into main

parents 4c33684f 0dd5c836
Loading
Loading
Loading
Loading
+100 −35
Original line number Diff line number Diff line
@@ -1088,16 +1088,24 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            return false;
        }
        // Only system installers can have an emergency installer
        if (PackageManager.PERMISSION_GRANTED
                != snapshot.checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid)
                && PackageManager.PERMISSION_GRANTED
                != snapshot.checkUidPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES, uid)
                && PackageManager.PERMISSION_GRANTED
                != snapshot.checkUidPermission(Manifest.permission.INSTALL_SELF_UPDATES, uid)) {
        if (!hasSystemInstallerPermissions(snapshot, uid)) {
            return false;
        }
        return (snapshot.checkUidPermission(Manifest.permission.EMERGENCY_INSTALL_PACKAGES,
                installerUid) == PackageManager.PERMISSION_GRANTED);
        return hasEmergencyInstallerPermission(snapshot, installerUid);
    }

    private static boolean hasSystemInstallerPermissions(Computer snapshot, int uid) {
        return (PackageManager.PERMISSION_GRANTED
                == snapshot.checkUidPermission(Manifest.permission.INSTALL_PACKAGES, uid)
                || PackageManager.PERMISSION_GRANTED
                == snapshot.checkUidPermission(Manifest.permission.INSTALL_PACKAGE_UPDATES, uid)
                || PackageManager.PERMISSION_GRANTED
                == snapshot.checkUidPermission(Manifest.permission.INSTALL_SELF_UPDATES, uid));
    }

    private static boolean hasEmergencyInstallerPermission(Computer snapshot, int installerUid) {
        return snapshot.checkUidPermission(Manifest.permission.EMERGENCY_INSTALL_PACKAGES,
                installerUid) == PackageManager.PERMISSION_GRANTED;
    }

    private static final int USER_ACTION_NOT_NEEDED = 0;
@@ -3123,40 +3131,75 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            // the emergency bypass.
            return false;
        }
        // Check if app being installed is the verifier itself.
        if (TextUtils.equals(verifierPackageName, packageName)) {
            Slog.d(TAG, "Bypassing developer verification because the verifier is being updated");
            return true;
        }
        // Check if app being installed is the sysconfig-specified update-owner of the verifier.
        final String updateOwnerPackageName = mPm.getSystemAppUpdateOwnerPackageName(
                verifierPackageName);
        if (updateOwnerPackageName == null) {
            // No sysconfig-specified update-owner for the verifier. No need to check further.
            // The verifier has not specified an update-owner in sysconfig.
            return false;
        }
        if (TextUtils.equals(updateOwnerPackageName, packageName)) {
            Slog.d(TAG, "Bypassing verification service because the sysconfig-specified "
                    + "update owner of the verifier is being updated");
            return true;
        final String installerPackageName = getInstallerPackageName();
        if (installerPackageName == null) {
            return false;
        }
        // Check if app being installed is the emergency installer of the sysconfig-specified
        // update-owner of the verifier.
        if (isEmergencyInstallerEnabled(updateOwnerPackageName, snapshot, userId, ps.getAppId())) {
        final PackageStateInternal psUpdateOwner = snapshot.getPackageStateInternal(
                updateOwnerPackageName, Process.SYSTEM_UID);
        if (psUpdateOwner == null || psUpdateOwner.getPkg() == null) {
                // Impossible condition, because the if clause above already checked this.
                // Added to prevent lint warnings.
                return false;
        }
            String emergencyInstallerPackageName = psUpdateOwner.getPkg().getEmergencyInstaller();
            if (emergencyInstallerPackageName != null
                    && TextUtils.equals(emergencyInstallerPackageName, packageName)) {
                Slog.d(TAG, "Bypassing verification service because the "
                        + "emergency installer of the verifier's update owner is being updated");
        // Validate the permissions of the sysconfig-specified update-owner
        if (!hasSystemInstallerPermissions(snapshot, psUpdateOwner.getAppId())) {
            return false;
        }
        // Check if the verifier is being updated, and the installer is the verifier's
        // sysconfig-specified update-owner.
        if (TextUtils.equals(verifierPackageName, packageName)
                && TextUtils.equals(updateOwnerPackageName, installerPackageName)) {
            Slog.d(TAG, "Bypassing developer verification because the verifier is being updated.");
            return true;
        }
        // Check if the verifier's sysconfig-specified update-owner is being updated, and the
        // installer is the verifier's sysconfig-specified update-owner.
        if (TextUtils.equals(updateOwnerPackageName, packageName)
                && TextUtils.equals(updateOwnerPackageName, installerPackageName)) {
            Slog.d(TAG, "Bypassing developer verification because the update-owner of the"
                    + " verifier which is specified in the sysconfig is being updated.");
            return true;
        }
        String emergencyInstallerOfUpdateOwner = psUpdateOwner.getPkg().getEmergencyInstaller();
        if (emergencyInstallerOfUpdateOwner == null) {
            // The rest of the bypass checks involve the emergency installer of the update-owner.
            // If this is no such emergency installer, no need to check further.
            return false;
        }
        final PackageStateInternal psEmergencyInstallerOfUpdateOwner =
                snapshot.getPackageStateInternal(emergencyInstallerOfUpdateOwner,
                        Process.SYSTEM_UID);
        if (psEmergencyInstallerOfUpdateOwner == null
                || psEmergencyInstallerOfUpdateOwner.getPkg() == null) {
            return false;
        }
        // Check the permission of the emergency installer
        if (!hasEmergencyInstallerPermission(
                snapshot, psEmergencyInstallerOfUpdateOwner.getAppId())) {
            return false;
        }
        // Check if the emergency installer of the verifier's sysconfig-specified update-owner is
        // being updated, and the installer is the verifier's sysconfig-specified update-owner.
        if (TextUtils.equals(emergencyInstallerOfUpdateOwner, packageName)
                && TextUtils.equals(updateOwnerPackageName, installerPackageName)) {
            Slog.d(TAG, "Bypassing developer verification because the emergency installer of"
                    + " the update-owner of the verifier which is specified in the sysconfig is"
                    + " being updated.");
            return true;
        }
        // If the app being installed is the sysconfig-specified update-owner, also allow bypassing
        // if the installer is the app's emergency-installer.
        if (TextUtils.equals(updateOwnerPackageName, packageName)
                && TextUtils.equals(emergencyInstallerOfUpdateOwner, installerPackageName)) {
            Slog.d(TAG, "Bypassing developer verification because the update-owner of the"
                    + " verifier which is specified in the sysconfig is being updated by its"
                    + " emergency installer.");
            return true;
        }
        return false;
    }
@@ -3460,6 +3503,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                    resumeVerify();
                    return;
                }
                if (shouldAllowDeveloperVerificationEmergencyBypass(
                        getPackageName(), mPm.snapshotComputer())) {
                    // Bypass verification when critical package is being updated and the
                    // verification result is not verified.
                    synchronized (mMetrics) {
                        mMetrics.onDeveloperVerificationBypassed(
                                DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY);
                    }
                    resumeVerify();
                    return;
                }

                // Package is blocked.
                mVerificationUserActionNeededReason =
@@ -3495,6 +3549,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                    resumeVerify();
                    return;
                }
                if (shouldAllowDeveloperVerificationEmergencyBypass(
                        getPackageName(), mPm.snapshotComputer())) {
                    // Bypass verification when critical package is being updated and the
                    // verification is incomplete.
                    synchronized (mMetrics) {
                        mMetrics.onDeveloperVerificationBypassed(
                                DEVELOPER_VERIFICATION_BYPASSED_REASON_EMERGENCY);
                    }
                    resumeVerify();
                    return;
                }

                StringBuilder sb = new StringBuilder(
                        "Verification cannot be completed because of ");
+91 −29
Original line number Diff line number Diff line
@@ -17,12 +17,12 @@ package com.android.server.pm

import android.content.Context
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED
import android.content.pm.PackageInstaller.DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_OPEN
import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_DEFAULT
import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_DENIED
import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED
import android.content.pm.PackageInstaller.DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED
import android.content.pm.PackageInstaller.DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_OPEN
import android.content.pm.PackageManager
import android.content.pm.verify.domain.DomainSet
import android.os.Parcel
@@ -200,14 +200,27 @@ class PackageInstallerSessionTest {
    @Test
    fun testShouldAllowDeveloperVerificationEmergencyBypassForVerifier() {
        val verifierPackageName = "verifierPackageName"
        val updateOwnerName = "updateOwnerPackageName"
        val mockPs = mock(PackageStateInternal::class.java)
        val mockUpdateOwnerPs = mock(PackageStateInternal::class.java)
        val mockUpdateOwnerPkg = mock(AndroidPackageInternal::class.java)
        val updateOwnerUid = 10200
        whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn(
            verifierPackageName)
        whenever(mockPs.isSystem).thenReturn(true)
        whenever(mSnapshot.getPackageStateInternal(
            eq(verifierPackageName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockPs)
        val session = createSession()
        whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName(
            anyString())).thenReturn(updateOwnerName)
        whenever(mSnapshot.getPackageStateInternal(
            eq(updateOwnerName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockUpdateOwnerPs)
        whenever(mockUpdateOwnerPs.pkg).thenReturn(mockUpdateOwnerPkg)
        whenever(mockUpdateOwnerPs.appId).thenReturn(updateOwnerUid)
        whenever(mSnapshot.checkUidPermission(anyString(), eq(updateOwnerUid)))
            .thenReturn(PackageManager.PERMISSION_GRANTED)
        val session = createSession(installerPackageName = updateOwnerName)
        assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass(
            verifierPackageName, mSnapshot)).isTrue()
    }
@@ -224,8 +237,8 @@ class PackageInstallerSessionTest {
            eq(updateOwnerName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockPs)
        whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName(
            anyString())).thenReturn(null)
        val session = createSession()
        eq(verifierPackageName))).thenReturn(null)
        val session = createSession(installerPackageName = updateOwnerName)
        assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass(
            updateOwnerName, mSnapshot)).isFalse()
    }
@@ -234,16 +247,22 @@ class PackageInstallerSessionTest {
    fun testShouldAllowDeveloperVerificationEmergencyBypassForUpdateOwner() {
        val verifierPackageName = "verifierPackageName"
        val updateOwnerName = "updateOwnerPackageName"
        val mockPs = mock(PackageStateInternal::class.java)
        val mockUpdateOwnerPs = mock(PackageStateInternal::class.java)
        val mockUpdateOwnerPkg = mock(AndroidPackageInternal::class.java)
        val updateOwnerUid = 10200
        whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn(
            verifierPackageName)
        whenever(mockPs.isSystem).thenReturn(true)
        whenever(mockUpdateOwnerPs.isSystem).thenReturn(true)
        whenever(mSnapshot.getPackageStateInternal(
            eq(updateOwnerName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockPs)
            .thenReturn(mockUpdateOwnerPs)
        whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName(
            eq(verifierPackageName))).thenReturn(updateOwnerName)
        val session = createSession()
        whenever(mockUpdateOwnerPs.pkg).thenReturn(mockUpdateOwnerPkg)
        whenever(mockUpdateOwnerPs.appId).thenReturn(updateOwnerUid)
        whenever(mSnapshot.checkUidPermission(anyString(), eq(updateOwnerUid)))
            .thenReturn(PackageManager.PERMISSION_GRANTED)
        val session = createSession(installerPackageName = updateOwnerName)
        assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass(
            updateOwnerName, mSnapshot)).isTrue()
    }
@@ -253,41 +272,83 @@ class PackageInstallerSessionTest {
        val verifierPackageName = "verifierPackageName"
        val updateOwnerName = "updateOwnerPackageName"
        val emergencyInstallerPackageName = "emergencyInstallerPackageName"
        val mockPs = mock(PackageStateInternal::class.java)
        val mockUpdateOwnerPs = mock(PackageStateInternal::class.java)
        val mockUpdateOwnerPkg = mock(AndroidPackageInternal::class.java)
        val mockUid = 10001
        val mockEmergencyInstallerPs = mock(PackageStateInternal::class.java)
        val mockEmergencyInstallerPkg = mock(AndroidPackageInternal::class.java)
        val mockEmergencyInstallerUid = 10001
        val mockUpdateOwnerUid = 10200
        whenever(mockPs.appId).thenReturn(mockUid)
        whenever(mockUpdateOwnerPs.appId).thenReturn(mockUpdateOwnerUid)
        whenever(mockUpdateOwnerPkg.emergencyInstaller).thenReturn(
            emergencyInstallerPackageName)

        whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn(
            verifierPackageName)
        whenever(mockPs.isSystem).thenReturn(true)
        whenever(mockUpdateOwnerPs.isSystem).thenReturn(true)
        whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName(
            eq(verifierPackageName))).thenReturn(updateOwnerName)

        whenever(mockUpdateOwnerPs.pkg).thenReturn(mockUpdateOwnerPkg)
        whenever(mockUpdateOwnerPs.appId).thenReturn(mockUpdateOwnerUid)
        whenever(mockUpdateOwnerPkg.emergencyInstaller).thenReturn(
            emergencyInstallerPackageName)
        whenever(mSnapshot.getPackageStateInternal(
            eq(updateOwnerName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockUpdateOwnerPs)
        whenever(mSnapshot.getPackageStateInternal(
            eq(updateOwnerName)))
            .thenReturn(mockUpdateOwnerPs)
        whenever(mSnapshot.getPackageStateInternal(
            eq(emergencyInstallerPackageName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockPs)
        whenever(mSnapshot.getPackagesForUid(eq(mockUid))).thenReturn(
            listOf(emergencyInstallerPackageName).toTypedArray())
        whenever(mSnapshot.checkUidPermission(anyString(),
            eq(UserHandle.getUid(USER_ID, mockUpdateOwnerUid))))
            .thenReturn(PackageManager.PERMISSION_GRANTED)
        whenever(mSnapshot.checkUidPermission(anyString(), eq(mockUid)))

        whenever(mSnapshot.getPackageStateInternal(
            eq(emergencyInstallerPackageName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockEmergencyInstallerPs)
        whenever(mockEmergencyInstallerPs.pkg).thenReturn(mockEmergencyInstallerPkg)
        whenever(mockEmergencyInstallerPs.appId).thenReturn(mockEmergencyInstallerUid)
        whenever(mockEmergencyInstallerPs.isSystem).thenReturn(true)
        whenever(mSnapshot.checkUidPermission(anyString(), eq(mockEmergencyInstallerUid)))
            .thenReturn(PackageManager.PERMISSION_GRANTED)

        val session = createSession(installerPackageName = updateOwnerName)
        assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass(
            emergencyInstallerPackageName, mSnapshot)).isTrue()
    }

    @Test
    fun testShouldAllowDeveloperVerificationEmergencyBypassForUpdaterOwnerByEmergencyInstaller() {
        val verifierPackageName = "verifierPackageName"
        val updateOwnerName = "updateOwnerPackageName"
        val emergencyInstallerPackageName = "emergencyInstallerPackageName"
        val mockUpdateOwnerPs = mock(PackageStateInternal::class.java)
        val mockUpdateOwnerPkg = mock(AndroidPackageInternal::class.java)
        val mockEmergencyInstallerPs = mock(PackageStateInternal::class.java)
        val mockEmergencyInstallerPkg = mock(AndroidPackageInternal::class.java)
        val mockEmergencyInstallerUid = 10001
        val mockUpdateOwnerUid = 10200

        whenever(mMockDeveloperVerifierController.verifierPackageName).thenReturn(
            verifierPackageName)
        whenever(mMockPackageManagerInternal.getSystemAppUpdateOwnerPackageName(
            eq(verifierPackageName))).thenReturn(updateOwnerName)
        val session = createSession()

        whenever(mSnapshot.getPackageStateInternal(
            eq(updateOwnerName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockUpdateOwnerPs)
        whenever(mockUpdateOwnerPs.appId).thenReturn(mockUpdateOwnerUid)
        whenever(mockUpdateOwnerPs.isSystem).thenReturn(true)
        whenever(mockUpdateOwnerPs.pkg).thenReturn(mockUpdateOwnerPkg)
        whenever(mSnapshot.checkUidPermission(anyString(),
            eq(UserHandle.getUid(USER_ID, mockUpdateOwnerUid))))
            .thenReturn(PackageManager.PERMISSION_GRANTED)

        whenever(mockUpdateOwnerPkg.emergencyInstaller).thenReturn(
            emergencyInstallerPackageName)
        whenever(mSnapshot.getPackageStateInternal(
            eq(emergencyInstallerPackageName), eq(Process.SYSTEM_UID)))
            .thenReturn(mockEmergencyInstallerPs)
        whenever(mockEmergencyInstallerPs.pkg).thenReturn(mockEmergencyInstallerPkg)
        whenever(mockEmergencyInstallerPs.appId).thenReturn(mockEmergencyInstallerUid)
        whenever(mSnapshot.checkUidPermission(anyString(), eq(mockEmergencyInstallerUid)))
            .thenReturn(PackageManager.PERMISSION_GRANTED)

        val session = createSession(installerPackageName = emergencyInstallerPackageName)
        assertThat(session.shouldAllowDeveloperVerificationEmergencyBypass(
            emergencyInstallerPackageName, mSnapshot)).isTrue()
            updateOwnerName, mSnapshot)).isTrue()
    }

    private fun createSession(
@@ -296,6 +357,7 @@ class PackageInstallerSessionTest {
        multiPackage: Boolean = false,
        parentSessionId: Int = PackageInstaller.SessionInfo.INVALID_ID,
        childSessionIds: List<Int> = emptyList(),
        installerPackageName: String = "testInstaller",
        block: (SessionParams) -> Unit = {},
    ): PackageInstallerSession {
        val bundle = PersistableBundle()
@@ -309,7 +371,7 @@ class PackageInstallerSessionTest {

        val installSource = InstallSource.create(
            "testInstallInitiator",
            "testInstallOriginator", "testInstaller", -1, "testUpdateOwner",
            "testInstallOriginator", installerPackageName, -1, "testUpdateOwner",
            "testAttributionTag", PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED
        )