diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index b0b2c33e0ddd1..37baae35734b6 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -55,4 +55,6 @@ interface IPackageInstaller { in IntentSender statusReceiver, int userId, in List whiteListedPermissions); void setPermissionsResult(int sessionId, boolean accepted); + + void bypassNextStagedInstallerCheck(boolean value); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 57908f3a4dacd..4cfd1ab73c9ea 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -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 sessions, int installerUid) { int count = 0; diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index b4eacf6226ce8..88f442c7b6a00 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -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 failedUninstalls = new LinkedList<>();