summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2019-02-27 22:41:03 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2019-02-27 22:41:03 +0000
commit6da4f3e928f43b19950211629202bab1864517f7 (patch)
treeed45347d4aeb1df9b8ef6c3e88fd1f8f0719f3c2
parentf5c792cae70c9d2bca4f8fa27ba1cd21358cd4e0 (diff)
parent8bbb815a7515232e59b719a0941b64828367c8de (diff)
Merge "Don't allow downgrade of apexes unless INSTALL_ALLOW_DOWNGRADE is set"
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java23
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceUtils.java31
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java34
3 files changed, 63 insertions, 25 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 80e794f2593e..487861fa31ea 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14346,27 +14346,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
if (dataOwnerPkg != null) {
- // If installed, the package will get access to data left on the device by its
- // predecessor. As a security measure, this is permited only if this is not a
- // version downgrade or if the predecessor package is marked as debuggable and
- // a downgrade is explicitly requested.
- //
- // On debuggable platform builds, downgrades are permitted even for
- // non-debuggable packages to make testing easier. Debuggable platform builds do
- // not offer security guarantees and thus it's OK to disable some security
- // mechanisms to make debugging/testing easier on those builds. However, even on
- // debuggable builds downgrades of packages are permitted only if requested via
- // installFlags. This is because we aim to keep the behavior of debuggable
- // platform builds as close as possible to the behavior of non-debuggable
- // platform builds.
- final boolean downgradeRequested =
- (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
- final boolean packageDebuggable =
- (dataOwnerPkg.applicationInfo.flags
- & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- final boolean downgradePermitted =
- (downgradeRequested) && ((Build.IS_DEBUGGABLE) || (packageDebuggable));
- if (!downgradePermitted) {
+ if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags,
+ dataOwnerPkg.applicationInfo.flags)) {
try {
checkDowngrade(dataOwnerPkg, pkgLite);
} catch (PackageManagerException e) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 6134d3098e3b..3218c8608d77 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -32,6 +32,7 @@ import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
@@ -796,6 +797,36 @@ public class PackageManagerServiceUtils {
}
/**
+ * Checks whenever downgrade of an app is permitted.
+ *
+ * @param installFlags flags of the current install.
+ * @param applicationFlags flags of the currently installed version of the app.
+ * @return {@code true} if downgrade is permitted according to the {@code installFlags} and
+ * {@code applicationFlags}.
+ */
+ public static boolean isDowngradePermitted(int installFlags, int applicationFlags) {
+ // If installed, the package will get access to data left on the device by its
+ // predecessor. As a security measure, this is permited only if this is not a
+ // version downgrade or if the predecessor package is marked as debuggable and
+ // a downgrade is explicitly requested.
+ //
+ // On debuggable platform builds, downgrades are permitted even for
+ // non-debuggable packages to make testing easier. Debuggable platform builds do
+ // not offer security guarantees and thus it's OK to disable some security
+ // mechanisms to make debugging/testing easier on those builds. However, even on
+ // debuggable builds downgrades of packages are permitted only if requested via
+ // installFlags. This is because we aim to keep the behavior of debuggable
+ // platform builds as close as possible to the behavior of non-debuggable
+ // platform builds.
+ final boolean downgradeRequested =
+ (installFlags & PackageManager.INSTALL_ALLOW_DOWNGRADE) != 0;
+ final boolean packageDebuggable =
+ (applicationFlags
+ & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ return (downgradeRequested) && ((Build.IS_DEBUGGABLE) || (packageDebuggable));
+ }
+
+ /**
* Copy package to the target location.
*
* @param packagePath absolute path to the package to be copied. Can be
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index fac383945afd..3ebf8052af93 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -144,12 +144,40 @@ public class StagingManager {
private boolean submitSessionToApexService(@NonNull PackageInstallerSession session,
List<PackageInstallerSession> childSessions,
ApexInfoList apexInfoList) {
- return mApexManager.submitStagedSession(
+ boolean submittedToApexd = mApexManager.submitStagedSession(
session.sessionId,
childSessions != null
? childSessions.stream().mapToInt(s -> s.sessionId).toArray() :
new int[]{},
apexInfoList);
+ if (!submittedToApexd) {
+ session.setStagedSessionFailed(
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+ "APEX staging failed, check logcat messages from apexd for more details.");
+ return false;
+ }
+ for (ApexInfo newPackage : apexInfoList.apexInfos) {
+ PackageInfo activePackage = mApexManager.getActivePackage(newPackage.packageName);
+ if (activePackage == null) {
+ continue;
+ }
+ long activeVersion = activePackage.applicationInfo.longVersionCode;
+ boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
+ session.params.installFlags, activePackage.applicationInfo.flags);
+ if (activeVersion > newPackage.versionCode && !allowsDowngrade) {
+ session.setStagedSessionFailed(
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+ "Downgrade of APEX package " + newPackage.packageName
+ + " is not allowed. Active version: " + activeVersion
+ + " attempted: " + newPackage.versionCode);
+
+ if (!mApexManager.abortActiveSession()) {
+ Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
+ }
+ return false;
+ }
+ }
+ return true;
}
private static boolean isApexSession(@NonNull PackageInstallerSession session) {
@@ -184,9 +212,7 @@ public class StagingManager {
}
if (!success) {
- session.setStagedSessionFailed(
- SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "APEX staging failed, check logcat messages from apexd for more details.");
+ // submitSessionToApexService will populate error.
return;
}