Merge "Don't allow downgrade of apexes unless INSTALL_ALLOW_DOWNGRADE is set"
This commit is contained in:
committed by
Android (Google) Code Review
commit
6da4f3e928
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -795,6 +796,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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user