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

Commit 672c759b authored by Sumedh Sen's avatar Sumedh Sen
Browse files

Fix NullPointerException in PIA when installing from Files app

* Added a null check while fetching packages by UID.
* Removed dependency on Intent.EXTRA_ORIGINATING_UID sent by DocumentsManager and DownloadsProvider since they were sent to PIA as INVALID_UID. Instead, PIA uses callingUid to determine if the install request comes from the above mentioned sources to bypass REQUEST_INSTALL_PACKAGES permission check.
* PIA iterates over all packages with a sharedUid to check if any of the packages in sharedUid have access to a target package having a content provider.


Bug: 277074364
Bug: 271500460
Test: adb push file.apk /sdcard/directory
      open preinstalled files app and install the apk
Change-Id: Ie2f8d251c558b677759cf4c05ebb016c743c4439
parent c7ac88d4
Loading
Loading
Loading
Loading
+31 −43
Original line number Diff line number Diff line
@@ -77,7 +77,21 @@ public class InstallStart extends Activity {
        }

        final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
        final int originatingUid = getOriginatingUid(sourceInfo);
        // Uid of the source package, coming from ActivityManager
        int callingUid = getLaunchedFromUid();
        if (callingUid == Process.INVALID_UID) {
            // Cannot reach ActivityManager. Aborting install.
            Log.e(LOG_TAG, "Could not determine the launching uid.");
        }
        // Uid of the source package, with a preference to uid from ApplicationInfo
        final int originatingUid = sourceInfo != null ? sourceInfo.uid : callingUid;

        if (callingUid == Process.INVALID_UID && sourceInfo == null) {
            mAbortInstall = true;
        }

        boolean isDocumentsManager = checkPermission(Manifest.permission.MANAGE_DOCUMENTS,
                -1, callingUid) == PackageManager.PERMISSION_GRANTED;
        boolean isTrustedSource = false;
        if (sourceInfo != null && sourceInfo.isPrivilegedApp()) {
            isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false) || (
@@ -86,7 +100,8 @@ public class InstallStart extends Activity {
                            == PackageManager.PERMISSION_GRANTED);
        }

        if (!isTrustedSource && originatingUid != Process.INVALID_UID) {
        if (!isTrustedSource && !isSystemDownloadsProvider(callingUid) && !isDocumentsManager
                && originatingUid != Process.INVALID_UID) {
            final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
            if (targetSdkVersion < 0) {
                Log.w(LOG_TAG, "Cannot get target sdk version for uid " + originatingUid);
@@ -144,7 +159,7 @@ public class InstallStart extends Activity {

            if (packageUri != null
                    && packageUri.getScheme().equals(ContentResolver.SCHEME_CONTENT)
                    && canPackageQuery(originatingUid, packageUri)) {
                    && canPackageQuery(callingUid, packageUri)) {
                // [IMPORTANT] This path is deprecated, but should still work. Only necessary
                // features should be added.

@@ -212,41 +227,6 @@ public class InstallStart extends Activity {
        return null;
    }

    /**
     * Get the originating uid if possible, or {@link Process#INVALID_UID} if not available
     *
     * @param sourceInfo The source of this installation
     * @return The UID of the installation source or INVALID_UID
     */
    private int getOriginatingUid(@Nullable ApplicationInfo sourceInfo) {
        // The originating uid from the intent. We only trust/use this if it comes from either
        // the document manager app or the downloads provider
        final int uidFromIntent = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                Process.INVALID_UID);

        final int callingUid;
        if (sourceInfo != null) {
            callingUid = sourceInfo.uid;
        } else {
            callingUid = getLaunchedFromUid();
            if (callingUid == Process.INVALID_UID) {
                // Cannot reach ActivityManager. Aborting install.
                Log.e(LOG_TAG, "Could not determine the launching uid.");
                mAbortInstall = true;
                return Process.INVALID_UID;
            }
        }
        if (checkPermission(Manifest.permission.MANAGE_DOCUMENTS, -1, callingUid)
                == PackageManager.PERMISSION_GRANTED) {
            return uidFromIntent;
        }
        if (isSystemDownloadsProvider(callingUid)) {
            return uidFromIntent;
        }
        // We don't trust uid from the intent. Use the calling uid instead.
        return callingUid;
    }

    private boolean isSystemDownloadsProvider(int uid) {
        final ProviderInfo downloadProviderPackage = getPackageManager().resolveContentProvider(
                DOWNLOADS_AUTHORITY, 0);
@@ -260,8 +240,7 @@ public class InstallStart extends Activity {
    }

    @NonNull
    private boolean canPackageQuery(int originatingUid, Uri packageUri) {
        String callingPackage = mPackageManager.getPackagesForUid(originatingUid)[0];
    private boolean canPackageQuery(int callingUid, Uri packageUri) {
        ProviderInfo info = mPackageManager.resolveContentProvider(packageUri.getAuthority(),
                PackageManager.ComponentInfoFlags.of(0));
        if (info == null) {
@@ -269,11 +248,20 @@ public class InstallStart extends Activity {
        }
        String targetPackage = info.packageName;

        String[] callingPackages = mPackageManager.getPackagesForUid(callingUid);
        if (callingPackages == null) {
            return false;
        }
        for (String callingPackage: callingPackages) {
            try {
            return mPackageManager.canPackageQuery(callingPackage, targetPackage);
                if (mPackageManager.canPackageQuery(callingPackage, targetPackage)) {
                    return true;
                }
            } catch (PackageManager.NameNotFoundException e) {
            return false;
                // no-op
            }
        }
        return false;
    }

    private boolean isCallerSessionOwner(int originatingUid, int sessionId) {