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

Commit 7623ac96 authored by Sumedh Sen's avatar Sumedh Sen
Browse files

Remove the resolved path of session's APK from user confirmation intent

Intent sent to the user for install confirmation includes the resolved
path of the session's base apk. A malicious app can modify this path, resulting
in the installer activity to show a different app icon and label in the
confirmation dialog.

To fix this, expose a SystemApi for getting the resolved path and
permission protect it with a privileged permission.

Bug: 269728874
Test: atest CtsPackageInstallTestCases:SessionTest
Change-Id: Ibe7fe3ab5e74e3e910d9f7bd5b6f3f2e3c0ca658
parent 8d85aaf0
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -272,6 +272,7 @@ package android {
    field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG";
    field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE";
    field public static final String READ_GLOBAL_APP_SEARCH_DATA = "android.permission.READ_GLOBAL_APP_SEARCH_DATA";
    field public static final String READ_INSTALLED_SESSION_PATHS = "android.permission.READ_INSTALLED_SESSION_PATHS";
    field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS";
    field public static final String READ_NETWORK_USAGE_HISTORY = "android.permission.READ_NETWORK_USAGE_HISTORY";
    field public static final String READ_OEM_UNLOCK_STATE = "android.permission.READ_OEM_UNLOCK_STATE";
@@ -3802,7 +3803,6 @@ package android.content.pm {
    field public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";
    field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE";
    field public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS";
    field public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH";
    field public static final int LOCATION_DATA_APP = 0; // 0x0
    field public static final int LOCATION_MEDIA_DATA = 2; // 0x2
    field public static final int LOCATION_MEDIA_OBB = 1; // 0x1
@@ -3839,6 +3839,7 @@ package android.content.pm {
    method public boolean getInstallAsVirtualPreload();
    method public int getPendingUserActionReason();
    method public boolean getRequestDowngrade();
    method @Nullable @RequiresPermission(android.Manifest.permission.READ_INSTALLED_SESSION_PATHS) public String getResolvedBaseApkPath();
    method public int getRollbackDataPolicy();
    method @NonNull public java.util.Set<java.lang.String> getWhitelistedRestrictedPermissions();
  }
+13 −11
Original line number Diff line number Diff line
@@ -333,17 +333,6 @@ public class PackageInstaller {
    @SystemApi
    public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE";

    /**
     * Path to the validated base APK for this session, which may point at an
     * APK inside the session (when the session defines the base), or it may
     * point at the existing base APK (when adding splits to an existing app).
     *
     * @hide
     */
    @SystemApi
    public static final String EXTRA_RESOLVED_BASE_PATH =
            "android.content.pm.extra.RESOLVED_BASE_PATH";

    /**
     * Streaming installation pending.
     * Caller should make sure DataLoader is able to prepare image and reinitiate the operation.
@@ -3549,6 +3538,19 @@ public class PackageInstaller {
            return referrerUri;
        }

        /**
         * @return the path to the validated base APK for this session, which may point at an
         * APK inside the session (when the session defines the base), or it may
         * point at the existing base APK (when adding splits to an existing app).
         *
         * @hide
         */
        @SystemApi
        @RequiresPermission(Manifest.permission.READ_INSTALLED_SESSION_PATHS)
        public @Nullable String getResolvedBaseApkPath() {
            return resolvedBaseCodePath;
        }

        /**
         * Get the value set in {@link SessionParams#setGrantedRuntimePermissions(String[])}.
         *
+9 −0
Original line number Diff line number Diff line
@@ -5421,6 +5421,15 @@
    <permission android:name="android.permission.INSTALL_DPC_PACKAGES"
                android:protectionLevel="signature|role" />

    <!-- @SystemApi Allows an application to read resolved paths to the APKs (Base and any splits)
         of a session based install.
         <p>Not for use by third-party applications.
         @hide
    -->
    <permission android:name="android.permission.READ_INSTALLED_SESSION_PATHS"
                android:protectionLevel="signature|installer" />
    <uses-permission android:name="android.permission.READ_INSTALLED_SESSION_PATHS" />

    <!-- Allows an application to use System Data Loaders.
         <p>Not for use by third-party applications.
         @hide
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
    <uses-permission android:name="android.permission.READ_INSTALL_SESSIONS" />
    <uses-permission android:name="android.permission.READ_INSTALLED_SESSION_PATHS" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />
    <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
+3 −4
Original line number Diff line number Diff line
@@ -374,16 +374,15 @@ public class PackageInstallerActivity extends AlertActivity {
            final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID,
                    -1 /* defaultValue */);
            final SessionInfo info = mInstaller.getSessionInfo(sessionId);
            final String resolvedBaseCodePath = intent.getStringExtra(
                    PackageInstaller.EXTRA_RESOLVED_BASE_PATH);
            if (info == null || !info.isSealed() || resolvedBaseCodePath == null) {
            String resolvedPath = info.getResolvedBaseApkPath();
            if (info == null || !info.isSealed() || resolvedPath == null) {
                Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
                finish();
                return;
            }

            mSessionId = sessionId;
            packageSource = Uri.fromFile(new File(resolvedBaseCodePath));
            packageSource = Uri.fromFile(new File(resolvedPath));
            mOriginatingURI = null;
            mReferrerURI = null;
            mPendingUserActionReason = info.getPendingUserActionReason();
Loading