Merge "Allow APK rollback without rollback capability on previous key" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d1833c1bfd
@@ -18819,9 +18819,11 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final VersionInfo versionInfo = request.versionInfos.get(installPackageName);
|
||||
final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
|
||||
final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
|
||||
final boolean isRollback = installArgs != null
|
||||
&& installArgs.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
|
||||
final boolean compatMatch = verifySignatures(signatureCheckPs,
|
||||
disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
|
||||
compareRecover);
|
||||
compareRecover, isRollback);
|
||||
// The new KeySets will be re-added later in the scanning process.
|
||||
if (compatMatch) {
|
||||
removeAppKeySetData = true;
|
||||
@@ -19791,6 +19793,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
|
||||
final boolean virtualPreload =
|
||||
((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
|
||||
final boolean isRollback = args.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
|
||||
@ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
|
||||
if (args.move != null) {
|
||||
// moving a complete application; perform an initial scan on the new install location
|
||||
@@ -19971,7 +19974,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
parsedPackage);
|
||||
// We don't care about disabledPkgSetting on install for now.
|
||||
final boolean compatMatch = verifySignatures(signatureCheckPs, null,
|
||||
parsedPackage.getSigningDetails(), compareCompat, compareRecover);
|
||||
parsedPackage.getSigningDetails(), compareCompat, compareRecover,
|
||||
isRollback);
|
||||
// The new KeySets will be re-added later in the scanning process.
|
||||
if (compatMatch) {
|
||||
synchronized (mLock) {
|
||||
@@ -20248,15 +20252,23 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
+ pkgName11);
|
||||
}
|
||||
} else {
|
||||
SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails();
|
||||
SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails();
|
||||
// default to original signature matching
|
||||
if (!parsedPackage.getSigningDetails().checkCapability(
|
||||
oldPackage.getSigningDetails(),
|
||||
if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails,
|
||||
SigningDetails.CertCapabilities.INSTALLED_DATA)
|
||||
&& !oldPackage.getSigningDetails().checkCapability(
|
||||
parsedPackage.getSigningDetails(),
|
||||
&& !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails,
|
||||
SigningDetails.CertCapabilities.ROLLBACK)) {
|
||||
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
|
||||
"New package has a different signature: " + pkgName11);
|
||||
// Allow the update to proceed if this is a rollback and the parsed
|
||||
// package's current signing key is the current signer or in the lineage
|
||||
// of the old package; this allows a rollback to a previously installed
|
||||
// version after an app's signing key has been rotated without requiring
|
||||
// the rollback capability on the previous signing key.
|
||||
if (!isRollback || !oldPkgSigningDetails.hasAncestorOrSelf(
|
||||
parsedPkgSigningDetails)) {
|
||||
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
|
||||
"New package has a different signature: " + pkgName11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -624,7 +624,7 @@ public class PackageManagerServiceUtils {
|
||||
*/
|
||||
public static boolean verifySignatures(PackageSetting pkgSetting,
|
||||
PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures,
|
||||
boolean compareCompat, boolean compareRecover)
|
||||
boolean compareCompat, boolean compareRecover, boolean isRollback)
|
||||
throws PackageManagerException {
|
||||
final String packageName = pkgSetting.name;
|
||||
boolean compatMatch = false;
|
||||
@@ -658,6 +658,13 @@ public class PackageManagerServiceUtils {
|
||||
match = matchSignatureInSystem(pkgSetting, disabledPkgSetting);
|
||||
}
|
||||
|
||||
if (!match && isRollback) {
|
||||
// Since a rollback can only be initiated for an APK previously installed on the
|
||||
// device allow rolling back to a previous signing key even if the rollback
|
||||
// capability has not been granted.
|
||||
match = pkgSetting.signatures.mSigningDetails.hasAncestorOrSelf(parsedSignatures);
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
|
||||
"Package " + packageName +
|
||||
|
||||
@@ -563,6 +563,7 @@ class Rollback {
|
||||
params.setRequestDowngrade(true);
|
||||
params.setRequiredInstalledVersionCode(
|
||||
pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode());
|
||||
params.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);
|
||||
if (isStaged()) {
|
||||
params.setStaged();
|
||||
}
|
||||
|
||||
@@ -1225,4 +1225,44 @@ public class RollbackTest {
|
||||
InstallUtils.dropShellPermissionIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an app can be rolled back to the previous signing key.
|
||||
*
|
||||
* <p>The rollback capability in the signing lineage allows an app to be updated to an APK
|
||||
* signed with a previous signing key in the lineage; however this often defeats the purpose
|
||||
* of key rotation as a compromised key could then be used to roll an app back to the previous
|
||||
* key. To avoid requiring the rollback capability to support app rollbacks the PackageManager
|
||||
* allows an app to be rolled back to the previous signing key if the rollback install reason
|
||||
* is set.
|
||||
*/
|
||||
@Test
|
||||
public void testRollbackAfterKeyRotation() throws Exception {
|
||||
try {
|
||||
InstallUtils.adoptShellPermissionIdentity(
|
||||
Manifest.permission.INSTALL_PACKAGES,
|
||||
Manifest.permission.DELETE_PACKAGES,
|
||||
Manifest.permission.TEST_MANAGE_ROLLBACKS,
|
||||
Manifest.permission.MANAGE_ROLLBACKS);
|
||||
|
||||
// Uninstall TestApp.A
|
||||
Uninstall.packages(TestApp.A);
|
||||
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
|
||||
|
||||
// Install v1 of the app with the original signing key (without rollbacks enabled).
|
||||
Install.single(TestApp.AOriginal1).commit();
|
||||
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
|
||||
|
||||
// Upgrade from v1 to v2 with the rotated signing key, with rollbacks enabled.
|
||||
Install.single(TestApp.ARotated2).setEnableRollback().commit();
|
||||
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
|
||||
|
||||
// Roll back the app.
|
||||
RollbackInfo available = waitForAvailableRollback(TestApp.A);
|
||||
RollbackUtils.rollback(available.getRollbackId());
|
||||
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
|
||||
} finally {
|
||||
InstallUtils.dropShellPermissionIdentity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user