diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 49 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/Settings.java | 10 |
2 files changed, 56 insertions, 3 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index b79e157..3e1647e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2860,6 +2860,38 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.SIGNATURE_NO_MATCH; } + private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) { + if (isExternal(scannedPkg)) { + return mSettings.isExternalDatabaseVersionOlderThan( + DatabaseVersion.SIGNATURE_MALFORMED_RECOVER); + } else { + return mSettings.isInternalDatabaseVersionOlderThan( + DatabaseVersion.SIGNATURE_MALFORMED_RECOVER); + } + } + + private int compareSignaturesRecover(PackageSignatures existingSigs, + PackageParser.Package scannedPkg) { + if (!isRecoverSignatureUpdateNeeded(scannedPkg)) { + return PackageManager.SIGNATURE_NO_MATCH; + } + + String msg = null; + try { + if (Signature.areEffectiveMatch(existingSigs.mSignatures, scannedPkg.mSignatures)) { + logCriticalInfo(Log.INFO, "Recovered effectively matching certificates for " + + scannedPkg.packageName); + return PackageManager.SIGNATURE_MATCH; + } + } catch (CertificateException e) { + msg = e.getMessage(); + } + + logCriticalInfo(Log.INFO, + "Failed to recover certificates for " + scannedPkg.packageName + ": " + msg); + return PackageManager.SIGNATURE_NO_MATCH; + } + @Override public String[] getPackagesForUid(int uid) { uid = UserHandle.getAppId(uid); @@ -4148,7 +4180,8 @@ public class PackageManagerService extends IPackageManager.Stub { if (ps != null && ps.codePath.equals(srcFile) && ps.timeStamp == srcFile.lastModified() - && !isCompatSignatureUpdateNeeded(pkg)) { + && !isCompatSignatureUpdateNeeded(pkg) + && !isRecoverSignatureUpdateNeeded(pkg)) { long mSigningKeySetId = ps.keySetData.getProperSigningKeySet(); if (ps.signatures.mSignatures != null && ps.signatures.mSignatures.length != 0 @@ -4423,6 +4456,10 @@ public class PackageManagerService extends IPackageManager.Stub { == PackageManager.SIGNATURE_MATCH; } if (!match) { + match = compareSignaturesRecover(pkgSetting.signatures, pkg) + == PackageManager.SIGNATURE_MATCH; + } + if (!match) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + pkg.packageName + " signatures do not match the " + "previously installed version; ignoring!"); @@ -4439,6 +4476,10 @@ public class PackageManagerService extends IPackageManager.Stub { == PackageManager.SIGNATURE_MATCH; } if (!match) { + match = compareSignaturesRecover(pkgSetting.sharedUser.signatures, pkg) + == PackageManager.SIGNATURE_MATCH; + } + if (!match) { throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE, "Package " + pkg.packageName + " has no signatures that match those in shared user " @@ -5386,6 +5427,9 @@ public class PackageManagerService extends IPackageManager.Stub { if (!pkgSetting.keySetData.isUsingUpgradeKeySets() || pkgSetting.sharedUser != null) { try { verifySignaturesLP(pkgSetting, pkg); + // We just determined the app is signed correctly, so bring + // over the latest parsed certs. + pkgSetting.signatures.mSignatures = pkg.mSignatures; } catch (PackageManagerException e) { if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw e; @@ -5418,7 +5462,8 @@ public class PackageManagerService extends IPackageManager.Stub { + pkg.packageName + " upgrade keys do not match the " + "previously installed version"); } else { - // signatures may have changed as result of upgrade + // We just determined the app is signed correctly, so bring + // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSignatures; } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 7de56c8..699adef 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -103,7 +103,7 @@ final class Settings { * Note that care should be taken to make sure all database upgrades are * idempotent. */ - private static final int CURRENT_DATABASE_VERSION = DatabaseVersion.SIGNATURE_END_ENTITY; + private static final int CURRENT_DATABASE_VERSION = DatabaseVersion.SIGNATURE_MALFORMED_RECOVER; /** * This class contains constants that can be referred to from upgrade code. @@ -121,6 +121,14 @@ final class Settings { * just the signing certificate. */ public static final int SIGNATURE_END_ENTITY = 2; + + /** + * There was a window of time in + * {@link android.os.Build.VERSION_CODES#LOLLIPOP} where we persisted + * certificates after potentially mutating them. To switch back to the + * original untouched certificates, we need to force a collection pass. + */ + public static final int SIGNATURE_MALFORMED_RECOVER = 3; } private static final boolean DEBUG_STOPPED = false; |