diff options
| author | 2019-02-27 22:41:03 +0000 | |
|---|---|---|
| committer | 2019-02-27 22:41:03 +0000 | |
| commit | 6da4f3e928f43b19950211629202bab1864517f7 (patch) | |
| tree | ed45347d4aeb1df9b8ef6c3e88fd1f8f0719f3c2 | |
| parent | f5c792cae70c9d2bca4f8fa27ba1cd21358cd4e0 (diff) | |
| parent | 8bbb815a7515232e59b719a0941b64828367c8de (diff) | |
Merge "Don't allow downgrade of apexes unless INSTALL_ALLOW_DOWNGRADE is set"
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; } |