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

Commit 30a1f13d authored by Jerry Chang's avatar Jerry Chang
Browse files

Limit stage install to system and whitelisted packges only (2/2)

Add a whitelist check to limit staged installers beside system and a pm
shell command to bypass the next staged installer check.

Bug: 148664742
Test: atest StagedInstallerTest StagedRollbackTest
Change-Id: Ie9297ad8c1b74c2e63a08c71f2279658661f9a32
parent 6651da43
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -55,4 +55,6 @@ interface IPackageInstaller {
            in IntentSender statusReceiver, int userId, in List<String> whiteListedPermissions);

    void setPermissionsResult(int sessionId, boolean accepted);

    void bypassNextStagedInstallerCheck(boolean value);
}
+21 −2
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ import com.android.internal.util.ImageUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.permission.PermissionManagerServiceInternal;

@@ -151,6 +152,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
    private final Callbacks mCallbacks;

    private volatile boolean mOkToSendBroadcasts = false;
    private volatile boolean mBypassNextStagedInstallerCheck = false;

    /**
     * File storing persisted {@link #mSessions} metadata.
@@ -541,7 +543,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
            }
        }

        if (Build.IS_DEBUGGABLE || isDowngradeAllowedForCaller(callingUid)) {
        if (Build.IS_DEBUGGABLE || isCalledBySystemOrShell(callingUid)) {
            params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
        } else {
            params.installFlags &= ~PackageManager.INSTALL_ALLOW_DOWNGRADE;
@@ -571,6 +573,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
            }
        }

        if (mBypassNextStagedInstallerCheck) {
            mBypassNextStagedInstallerCheck = false;
        } else if (params.isStaged
                && !isCalledBySystemOrShell(callingUid)
                && !isWhitelistedStagedInstaller(requestedInstallerPackageName)) {
            throw new SecurityException("Installer not allowed to commit staged install");
        }

        if (!params.isMultiPackage) {
            // Only system components can circumvent runtime permissions when installing.
            if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
@@ -683,11 +693,15 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        return sessionId;
    }

    private boolean isDowngradeAllowedForCaller(int callingUid) {
    private boolean isCalledBySystemOrShell(int callingUid) {
        return callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID
                || callingUid == Process.SHELL_UID;
    }

    private boolean isWhitelistedStagedInstaller(String installerName) {
        return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName);
    }

    @Override
    public void updateSessionAppIcon(int sessionId, Bitmap appIcon) {
        synchronized (mSessions) {
@@ -963,6 +977,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        }
    }

    @Override
    public void bypassNextStagedInstallerCheck(boolean value) {
        mBypassNextStagedInstallerCheck = value;
    }

    private static int getSessionCount(SparseArray<PackageInstallerSession> sessions,
            int installerUid) {
        int count = 0;
+16 −0
Original line number Diff line number Diff line
@@ -297,6 +297,8 @@ class PackageManagerShellCommand extends ShellCommand {
                    return runGetModuleInfo();
                case "log-visibility":
                    return runLogVisibility();
                case "bypass-staged-installer-check":
                    return runBypassStagedInstallerCheck();
                default: {
                    String nextArg = getNextArg();
                    if (nextArg == null) {
@@ -392,6 +394,20 @@ class PackageManagerShellCommand extends ShellCommand {
        return 1;
    }

    private int runBypassStagedInstallerCheck() {
        final PrintWriter pw = getOutPrintWriter();
        try {
            mInterface.getPackageInstaller()
                    .bypassNextStagedInstallerCheck(Boolean.parseBoolean(getNextArg()));
            return 0;
        } catch (RemoteException e) {
            pw.println("Failure ["
                    + e.getClass().getName() + " - "
                    + e.getMessage() + "]");
            return -1;
        }
    }

    private int uninstallSystemUpdates() {
        final PrintWriter pw = getOutPrintWriter();
        List<String> failedUninstalls = new LinkedList<>();