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

Commit 51f2d0a6 authored by Ivan Chiang's avatar Ivan Chiang
Browse files

[PM] Use the originating uid from the intent if needed for V2

If the intent is from the system document app or the system downloads
provider, we can trust it to use the originating uid from it. It can
show the correct install information from the uid.

Flag: EXEMPT Bug fix
Test: atest CtsPackageInstallerCUJInstallationTestCasesV2
Test: atest CtsPackageInstallerCUJUpdateOwnerShipTestCasesV2
Test: manual. Enable Pia V2
      1. Download one app via 3rd party browser
      2. Uninstall the 3rd party browser
      3. Start the Documentsui -> Downloads root
      4. Click the APK
Bug: 419738096
Change-Id: I28fe1296d36fa1b0ca76962b892f99976aa9aeaa
parent a1ea8369
Loading
Loading
Loading
Loading
+42 −7
Original line number Original line Diff line number Diff line
@@ -112,6 +112,12 @@ class InstallRepository(private val context: Context) {
     * apps.
     * apps.
     */
     */
    private var originatingUid = Process.INVALID_UID
    private var originatingUid = Process.INVALID_UID
    /**
     * UID of the origin of the installation from the sessionInfo. This UID is used to fetch the
     * update-ownership app-label of the source of the install, and also check whether the source
     * app has the AppOp to install other apps.
     */
    private var originatingUidFromSessionInfo = Process.INVALID_UID
    private var callingPackage: String? = null
    private var callingPackage: String? = null
    private var sessionStager: SessionStager? = null
    private var sessionStager: SessionStager? = null
    private lateinit var intent: Intent
    private lateinit var intent: Intent
@@ -160,7 +166,20 @@ class InstallRepository(private val context: Context) {
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
        }
        }


        // By default, the originatingUid is callingUid. If the caller is the system download
        // provider or the documents manager, we parse the originatingUid from the
        // Intent.EXTRA_ORIGINATING_UID. And we check the appOps permission for the originatingUid
        // later.
        originatingUid = callingUid
        originatingUid = callingUid
        if (PackageUtil.isDocumentsManager(context, callingUid)
            || PackageUtil.getSystemDownloadsProviderInfo(
                context.packageManager, callingUid) != null) {
            // The originating uid from the intent. We only trust/use this if it comes from either
            // the document manager app or the downloads provider. It may be Process.INVALID_UID if
            // the original owner App is not installed on the device now.
            originatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID, Process.INVALID_UID)
        }

        val sessionInfo: SessionInfo? =
        val sessionInfo: SessionInfo? =
            if (sessionId != SessionInfo.INVALID_ID)
            if (sessionId != SessionInfo.INVALID_ID)
                packageInstaller.getSessionInfo(sessionId)
                packageInstaller.getSessionInfo(sessionId)
@@ -168,7 +187,7 @@ class InstallRepository(private val context: Context) {
        if (sessionInfo != null) {
        if (sessionInfo != null) {
            callingAttributionTag = sessionInfo.installerAttributionTag
            callingAttributionTag = sessionInfo.installerAttributionTag
            if (sessionInfo.originatingUid != Process.INVALID_UID) {
            if (sessionInfo.originatingUid != Process.INVALID_UID) {
                originatingUid = sessionInfo.originatingUid
                originatingUidFromSessionInfo = sessionInfo.originatingUid
            }
            }
        }
        }


@@ -186,6 +205,7 @@ class InstallRepository(private val context: Context) {
                    "calling package: $callingPackage\n" +
                    "calling package: $callingPackage\n" +
                    "callingUid: $callingUid\n" +
                    "callingUid: $callingUid\n" +
                    "originatingUid: $originatingUid\n" +
                    "originatingUid: $originatingUid\n" +
                    "originatingUidFromSessionInfo: $originatingUidFromSessionInfo\n" +
                    "sourceInfo: $sourceInfo"
                    "sourceInfo: $sourceInfo"
            )
            )
        }
        }
@@ -203,8 +223,14 @@ class InstallRepository(private val context: Context) {
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
        }
        }


        isTrustedSource = isInstallRequestFromTrustedSource(sourceInfo, this.intent, callingUid)
        isTrustedSource = isInstallRequestFromTrustedSource(sourceInfo, this.intent, originatingUid)
        if (!isInstallPermissionGrantedOrRequested(context, callingUid, isTrustedSource)) {
        // In general case, the originatingUid is callingUid. If callingUid is INVALID_UID, return
        // InstallAborted in the check above. When the originatingUid is INVALID_UID here, it means
        // the originatingUid is from the system download manager or the system documents manager,
        // and the package doesn't exist on the device. For this case, we don't need to check the
        // permission for the originatingUid. The package doesn't exist.
        if (originatingUid != Process.INVALID_UID
            && !isInstallPermissionGrantedOrRequested(context, originatingUid, isTrustedSource)) {
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
        }
        }


@@ -241,8 +267,8 @@ class InstallRepository(private val context: Context) {
    ): Boolean {
    ): Boolean {
        val isPrivilegedAndKnown = sourceInfo != null && sourceInfo.isPrivilegedApp &&
        val isPrivilegedAndKnown = sourceInfo != null && sourceInfo.isPrivilegedApp &&
            intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)
            intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)
        val isInstallPkgPermissionGranted =
        val isInstallPkgPermissionGranted = callingUid != Process.INVALID_UID
            isPermissionGranted(context, Manifest.permission.INSTALL_PACKAGES, callingUid)
                && isPermissionGranted(context, Manifest.permission.INSTALL_PACKAGES, callingUid)


        return isPrivilegedAndKnown || isInstallPkgPermissionGranted
        return isPrivilegedAndKnown || isInstallPkgPermissionGranted
    }
    }
@@ -398,7 +424,9 @@ class InstallRepository(private val context: Context) {
        params.setOriginatingUri(
        params.setOriginatingUri(
            intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI, Uri::class.java)
            intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI, Uri::class.java)
        )
        )
        if (originatingUid != Process.INVALID_UID) {
            params.setOriginatingUid(originatingUid)
            params.setOriginatingUid(originatingUid)
        }
        params.setInstallerPackageName(intent.getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME))
        params.setInstallerPackageName(intent.getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME))
        params.setInstallReason(PackageManager.INSTALL_REASON_USER)
        params.setInstallReason(PackageManager.INSTALL_REASON_USER)
        // Disable full screen intent usage by for sideloads.
        // Disable full screen intent usage by for sideloads.
@@ -690,8 +718,15 @@ class InstallRepository(private val context: Context) {
            !TextUtils.isEmpty(existingUpdateOwnerLabel) &&
            !TextUtils.isEmpty(existingUpdateOwnerLabel) &&
            userActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP
            userActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP
        ) {
        ) {
            // In the update-ownership case, the callingUid is not from the download manager
            // or documents manager. The originatingUid should not be INVALID_UID, it should be
            // callingUid in this case. It is not INVALID_UID.
            var uid = originatingUidFromSessionInfo
            if (uid == Process.INVALID_UID) {
                uid = originatingUid
            }
            val originatingPackageName =
            val originatingPackageName =
                getPackageNameForUid(context, originatingUid, callingPackage)
                getPackageNameForUid(context, uid, callingPackage)
            getApplicationLabel(originatingPackageName)
            getApplicationLabel(originatingPackageName)
        } else {
        } else {
            null
            null
+14 −9
Original line number Original line Diff line number Diff line
@@ -87,7 +87,8 @@ object PackageUtil {
     * @return [ApplicationInfo] of the provider if a downloads provider exists, it is a
     * @return [ApplicationInfo] of the provider if a downloads provider exists, it is a
     * system app, and its UID matches with the passed UID, null otherwise.
     * system app, and its UID matches with the passed UID, null otherwise.
     */
     */
    private fun getSystemDownloadsProviderInfo(pm: PackageManager, uid: Int): ApplicationInfo? {
    @JvmStatic
    fun getSystemDownloadsProviderInfo(pm: PackageManager, uid: Int): ApplicationInfo? {
        // Check if there are currently enabled downloads provider on the system.
        // Check if there are currently enabled downloads provider on the system.
        val providerInfo = pm.resolveContentProvider(DOWNLOADS_AUTHORITY, 0)
        val providerInfo = pm.resolveContentProvider(DOWNLOADS_AUTHORITY, 0)
            ?: return null
            ?: return null
@@ -166,6 +167,16 @@ object PackageUtil {
        return pm.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED
        return pm.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED
    }
    }


    /**
     * @param context the [Context] object
     * @param callingUid the UID of the caller who's permission is being checked
     * @return `true` if the callingUid is granted the documents permission
     */
    @JvmStatic
    fun isDocumentsManager(context: Context, callingUid: Int): Boolean {
        return isPermissionGranted(context, Manifest.permission.MANAGE_DOCUMENTS, callingUid)
    }

    /**
    /**
     * @param context the [Context] object
     * @param context the [Context] object
     * @param callingUid the UID of the caller of Pia
     * @param callingUid the UID of the caller of Pia
@@ -173,8 +184,7 @@ object PackageUtil {
     * that has passed EXTRA_NOT_UNKNOWN_SOURCE as `true` in the installation intent, or an app that
     * that has passed EXTRA_NOT_UNKNOWN_SOURCE as `true` in the installation intent, or an app that
     * has the [INSTALL_PACKAGES][Manifest.permission.INSTALL_PACKAGES] permission granted.
     * has the [INSTALL_PACKAGES][Manifest.permission.INSTALL_PACKAGES] permission granted.
     *
     *
     * @return `true` if the package is either a system downloads provider, a document manager,
     * @return `true` if the package is a trusted source, or has declared the
     * a trusted source, or has declared the
     * [REQUEST_INSTALL_PACKAGES][Manifest.permission.REQUEST_INSTALL_PACKAGES] in its manifest.
     * [REQUEST_INSTALL_PACKAGES][Manifest.permission.REQUEST_INSTALL_PACKAGES] in its manifest.
     */
     */
    @JvmStatic
    @JvmStatic
@@ -183,12 +193,7 @@ object PackageUtil {
        callingUid: Int,
        callingUid: Int,
        isTrustedSource: Boolean,
        isTrustedSource: Boolean,
    ): Boolean {
    ): Boolean {
        val isDocumentsManager =
        if (!isTrustedSource) {
            isPermissionGranted(context, Manifest.permission.MANAGE_DOCUMENTS, callingUid)
        val isSystemDownloadsProvider =
            getSystemDownloadsProviderInfo(context.packageManager, callingUid) != null

        if (!isTrustedSource && !isSystemDownloadsProvider && !isDocumentsManager) {
            val targetSdkVersion = getMaxTargetSdkVersionForUid(context, callingUid)
            val targetSdkVersion = getMaxTargetSdkVersionForUid(context, callingUid)
            if (targetSdkVersion < 0) {
            if (targetSdkVersion < 0) {
                // Invalid calling uid supplied. Abort install.
                // Invalid calling uid supplied. Abort install.