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 VersionInfo versionInfo = request.versionInfos.get(installPackageName);
|
||||||
final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
|
final boolean compareCompat = isCompatSignatureUpdateNeeded(versionInfo);
|
||||||
final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
|
final boolean compareRecover = isRecoverSignatureUpdateNeeded(versionInfo);
|
||||||
|
final boolean isRollback = installArgs != null
|
||||||
|
&& installArgs.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
|
||||||
final boolean compatMatch = verifySignatures(signatureCheckPs,
|
final boolean compatMatch = verifySignatures(signatureCheckPs,
|
||||||
disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
|
disabledPkgSetting, parsedPackage.getSigningDetails(), compareCompat,
|
||||||
compareRecover);
|
compareRecover, isRollback);
|
||||||
// The new KeySets will be re-added later in the scanning process.
|
// The new KeySets will be re-added later in the scanning process.
|
||||||
if (compatMatch) {
|
if (compatMatch) {
|
||||||
removeAppKeySetData = true;
|
removeAppKeySetData = true;
|
||||||
@@ -19791,6 +19793,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
|
final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
|
||||||
final boolean virtualPreload =
|
final boolean virtualPreload =
|
||||||
((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
|
((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
|
||||||
|
final boolean isRollback = args.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
|
||||||
@ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
|
@ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
|
||||||
if (args.move != null) {
|
if (args.move != null) {
|
||||||
// moving a complete application; perform an initial scan on the new install location
|
// moving a complete application; perform an initial scan on the new install location
|
||||||
@@ -19971,7 +19974,8 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
parsedPackage);
|
parsedPackage);
|
||||||
// We don't care about disabledPkgSetting on install for now.
|
// We don't care about disabledPkgSetting on install for now.
|
||||||
final boolean compatMatch = verifySignatures(signatureCheckPs, null,
|
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.
|
// The new KeySets will be re-added later in the scanning process.
|
||||||
if (compatMatch) {
|
if (compatMatch) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
@@ -20248,15 +20252,23 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
+ pkgName11);
|
+ pkgName11);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
SigningDetails parsedPkgSigningDetails = parsedPackage.getSigningDetails();
|
||||||
|
SigningDetails oldPkgSigningDetails = oldPackage.getSigningDetails();
|
||||||
// default to original signature matching
|
// default to original signature matching
|
||||||
if (!parsedPackage.getSigningDetails().checkCapability(
|
if (!parsedPkgSigningDetails.checkCapability(oldPkgSigningDetails,
|
||||||
oldPackage.getSigningDetails(),
|
|
||||||
SigningDetails.CertCapabilities.INSTALLED_DATA)
|
SigningDetails.CertCapabilities.INSTALLED_DATA)
|
||||||
&& !oldPackage.getSigningDetails().checkCapability(
|
&& !oldPkgSigningDetails.checkCapability(parsedPkgSigningDetails,
|
||||||
parsedPackage.getSigningDetails(),
|
|
||||||
SigningDetails.CertCapabilities.ROLLBACK)) {
|
SigningDetails.CertCapabilities.ROLLBACK)) {
|
||||||
throw new PrepareFailure(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
|
// Allow the update to proceed if this is a rollback and the parsed
|
||||||
"New package has a different signature: " + pkgName11);
|
// 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,
|
public static boolean verifySignatures(PackageSetting pkgSetting,
|
||||||
PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures,
|
PackageSetting disabledPkgSetting, PackageParser.SigningDetails parsedSignatures,
|
||||||
boolean compareCompat, boolean compareRecover)
|
boolean compareCompat, boolean compareRecover, boolean isRollback)
|
||||||
throws PackageManagerException {
|
throws PackageManagerException {
|
||||||
final String packageName = pkgSetting.name;
|
final String packageName = pkgSetting.name;
|
||||||
boolean compatMatch = false;
|
boolean compatMatch = false;
|
||||||
@@ -658,6 +658,13 @@ public class PackageManagerServiceUtils {
|
|||||||
match = matchSignatureInSystem(pkgSetting, disabledPkgSetting);
|
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) {
|
if (!match) {
|
||||||
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
|
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
|
||||||
"Package " + packageName +
|
"Package " + packageName +
|
||||||
|
|||||||
@@ -563,6 +563,7 @@ class Rollback {
|
|||||||
params.setRequestDowngrade(true);
|
params.setRequestDowngrade(true);
|
||||||
params.setRequiredInstalledVersionCode(
|
params.setRequiredInstalledVersionCode(
|
||||||
pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode());
|
pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode());
|
||||||
|
params.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);
|
||||||
if (isStaged()) {
|
if (isStaged()) {
|
||||||
params.setStaged();
|
params.setStaged();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1225,4 +1225,44 @@ public class RollbackTest {
|
|||||||
InstallUtils.dropShellPermissionIdentity();
|
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