diff options
author | dcashman <dcashman@google.com> | 2015-06-03 14:46:47 -0700 |
---|---|---|
committer | dcashman <dcashman@google.com> | 2015-06-15 17:14:54 -0700 |
commit | 87f794f0bf8b53d6c983968f398c4bde4cb6a014 (patch) | |
tree | 5a40a1d1e300edb43acf69a27291752648067b6a /services/core | |
parent | 31104fbb7e109e9fe34a09878e4901761fa39f5d (diff) | |
download | frameworks_base-87f794f0bf8b53d6c983968f398c4bde4cb6a014.zip frameworks_base-87f794f0bf8b53d6c983968f398c4bde4cb6a014.tar.gz frameworks_base-87f794f0bf8b53d6c983968f398c4bde4cb6a014.tar.bz2 |
Make keysetmgrservice gurantees explicit.
Add exceptions/checks for keysetmgrservice interractions which *should* never
happen, but would result in NPE or invalid metadata. Also handle mismatches
between package and keyset metadata in packages.xml.
Bug: 20128916
Change-Id: Ia0f63f78d232d9d8d9fbe4cd8e6cc3406e5192a7
Diffstat (limited to 'services/core')
-rw-r--r-- | services/core/java/com/android/server/pm/KeySetManagerService.java | 118 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 33 |
2 files changed, 116 insertions, 35 deletions
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java index 1ee07a5..0de0c92 100644 --- a/services/core/java/com/android/server/pm/KeySetManagerService.java +++ b/services/core/java/com/android/server/pm/KeySetManagerService.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; + +import com.android.internal.util.Preconditions; import android.content.pm.PackageParser; import android.util.ArrayMap; import android.util.ArraySet; @@ -98,6 +101,7 @@ public class KeySetManagerService { mRefCount++; return; } + public long decrRefCountLPw() { mRefCount--; return mRefCount; @@ -168,25 +172,82 @@ public class KeySetManagerService { } /** + * addScannedPackageLPw directly modifies the package metadata in pm.Settings + * at a point of no-return. We need to make sure that the scanned package does + * not contain bad keyset meta-data that could generate an incorrect + * PackageSetting. Verify that there is a signing keyset, there are no issues + * with null objects, and the upgrade and defined keysets match. + * + * Returns true if the package can safely be added to the keyset metadata. + */ + public void assertScannedPackageValid(PackageParser.Package pkg) + throws PackageManagerException { + if (pkg == null || pkg.packageName == null) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Passed invalid package to keyset validation."); + } + ArraySet<PublicKey> signingKeys = pkg.mSigningKeys; + if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has invalid signing-key-set."); + } + ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping; + if (definedMapping != null) { + if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has null defined key set."); + } + int defMapSize = definedMapping.size(); + for (int i = 0; i < defMapSize; i++) { + if (!(definedMapping.valueAt(i).size() > 0) + || definedMapping.valueAt(i).contains(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has null/no public keys for defined key-sets."); + } + } + } + ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets; + if (upgradeAliases != null) { + if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has upgrade-key-sets without corresponding definitions."); + } + } + } + + public void addScannedPackageLPw(PackageParser.Package pkg) { + Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms."); + Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms."); + PackageSetting ps = mPackages.get(pkg.packageName); + Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName + + "does not have a corresponding entry in mPackages."); + addSigningKeySetToPackageLPw(ps, pkg.mSigningKeys); + if (pkg.mKeySetMapping != null) { + addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping); + if (pkg.mUpgradeKeySets != null) { + addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets); + } + } + } + + /** * Informs the system that the given package was signed by the provided KeySet. */ - public void addSigningKeySetToPackageLPw(String packageName, + void addSigningKeySetToPackageLPw(PackageSetting pkg, ArraySet<PublicKey> signingKeys) { /* check existing keyset for reuse or removal */ - PackageSetting pkg = mPackages.get(packageName); long signingKeySetId = pkg.keySetData.getProperSigningKeySet(); if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) { ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId); - if (existingKeys.equals(signingKeys)) { + if (existingKeys != null && existingKeys.equals(signingKeys)) { /* no change in signing keys, leave PackageSetting alone */ return; } else { /* old keyset no longer valid, remove ref */ - KeySetHandle ksh = mKeySets.get(signingKeySetId); decrementKeySetLPw(signingKeySetId); } } @@ -212,13 +273,12 @@ public class KeySetManagerService { return KEYSET_NOT_FOUND; } - /* + /** * Inform the system that the given package defines the given KeySets. * Remove any KeySets the package no longer defines. */ - public void addDefinedKeySetsToPackageLPw(String packageName, + void addDefinedKeySetsToPackageLPw(PackageSetting pkg, ArrayMap<String, ArraySet<PublicKey>> definedMapping) { - PackageSetting pkg = mPackages.get(packageName); ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases(); /* add all of the newly defined KeySets */ @@ -227,7 +287,7 @@ public class KeySetManagerService { for (int i = 0; i < defMapSize; i++) { String alias = definedMapping.keyAt(i); ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i); - if (alias != null && pubKeys != null && pubKeys.size() > 0) { + if (alias != null && pubKeys != null || pubKeys.size() > 0) { KeySetHandle ks = addKeySetLPw(pubKeys); newKeySetAliases.put(alias, ks.getId()); } @@ -250,9 +310,8 @@ public class KeySetManagerService { * alias in its manifest to be an upgradeKeySet. This must be called * after all of the defined KeySets have been added. */ - public void addUpgradeKeySetsToPackageLPw(String packageName, - ArraySet<String> upgradeAliases) { - PackageSetting pkg = mPackages.get(packageName); + void addUpgradeKeySetsToPackageLPw(PackageSetting pkg, + ArraySet<String> upgradeAliases) { final int uaSize = upgradeAliases.size(); for (int i = 0; i < uaSize; i++) { pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i)); @@ -290,11 +349,11 @@ public class KeySetManagerService { * identify a {@link KeySetHandle}. */ public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) { - if(mKeySetMapping.get(id) == null) { + ArraySet<Long> pkIds = mKeySetMapping.get(id); + if (pkIds == null) { return null; } ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>(); - ArraySet<Long> pkIds = mKeySetMapping.get(id); final int pkSize = pkIds.size(); for (int i = 0; i < pkSize; i++) { mPubKeys.add(mPublicKeys.get(pkIds.valueAt(i)).getKey()); @@ -376,6 +435,10 @@ public class KeySetManagerService { */ private void decrementKeySetLPw(long id) { KeySetHandle ks = mKeySets.get(id); + if (ks == null) { + /* nothing to do */ + return; + } if (ks.decrRefCountLPw() <= 0) { ArraySet<Long> pubKeys = mKeySetMapping.get(id); final int pkSize = pubKeys.size(); @@ -385,7 +448,6 @@ public class KeySetManagerService { mKeySets.delete(id); mKeySetMapping.delete(id); } - return; } /* @@ -394,16 +456,20 @@ public class KeySetManagerService { */ private void decrementPublicKeyLPw(long id) { PublicKeyHandle pk = mPublicKeys.get(id); + if (pk == null) { + /* nothing to do */ + return; + } if (pk.decrRefCountLPw() <= 0) { mPublicKeys.delete(id); } - return; } /** * Adds the given PublicKey to the system, deduping as it goes. */ private long addPublicKeyLPw(PublicKey key) { + Preconditions.checkNotNull(key, "Cannot add null public key!"); long id = getIdForPublicKeyLPr(key); if (id != PUBLIC_KEY_NOT_FOUND) { @@ -473,6 +539,8 @@ public class KeySetManagerService { /* remove refs from common keysets and public keys */ PackageSetting pkg = mPackages.get(packageName); + Preconditions.checkNotNull(pkg, "pkg name: " + packageName + + "does not have a corresponding entry in mPackages."); long signingKeySetId = pkg.keySetData.getProperSigningKeySet(); decrementKeySetLPw(signingKeySetId); ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases(); @@ -715,16 +783,36 @@ public class KeySetManagerService { final int numRefCounts = keySetRefCounts.size(); for (int i = 0; i < numRefCounts; i++) { KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i)); + if (ks == null) { + /* something went terribly wrong and we have references to a non-existent key-set */ + Slog.wtf(TAG, "Encountered non-existent key-set reference when reading settings"); + continue; + } ks.setRefCountLPw(keySetRefCounts.valueAt(i)); } + /* + * In case something went terribly wrong and we have keysets with no associated packges + * that refer to them, record the orphaned keyset ids, and remove them using + * decrementKeySetLPw() after all keyset references have been set so that the associtaed + * public keys have the appropriate references from all keysets. + */ + ArraySet<Long> orphanedKeySets = new ArraySet<Long>(); final int numKeySets = mKeySets.size(); for (int i = 0; i < numKeySets; i++) { + if (mKeySets.valueAt(i).getRefCountLPr() == 0) { + Slog.wtf(TAG, "Encountered key-set w/out package references when reading settings"); + orphanedKeySets.add(mKeySets.keyAt(i)); + } ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i); final int pkSize = pubKeys.size(); for (int j = 0; j < pkSize; j++) { mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw(); } } + final int numOrphans = orphanedKeySets.size(); + for (int i = 0; i < numOrphans; i++) { + decrementKeySetLPw(orphanedKeySets.valueAt(i)); + } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index bc9e07b..6e832ed 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5110,16 +5110,18 @@ public class PackageManagerService extends IPackageManager.Stub { && !isCompatSignatureUpdateNeeded(pkg) && !isRecoverSignatureUpdateNeeded(pkg)) { long mSigningKeySetId = ps.keySetData.getProperSigningKeySet(); + KeySetManagerService ksms = mSettings.mKeySetManagerService; + ArraySet<PublicKey> signingKs; + synchronized (mPackages) { + signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId); + } if (ps.signatures.mSignatures != null && ps.signatures.mSignatures.length != 0 - && mSigningKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) { + && signingKs != null) { // Optimization: reuse the existing cached certificates // if the package appears to be unchanged. pkg.mSignatures = ps.signatures.mSignatures; - KeySetManagerService ksms = mSettings.mKeySetManagerService; - synchronized (mPackages) { - pkg.mSigningKeys = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId); - } + pkg.mSigningKeys = signingKs; return; } @@ -6591,6 +6593,10 @@ public class PackageManagerService extends IPackageManager.Stub { } } + // Make sure we're not adding any bogus keyset info + KeySetManagerService ksms = mSettings.mKeySetManagerService; + ksms.assertScannedPackageValid(pkg); + // writer synchronized (mPackages) { // We don't expect installation to fail beyond this point @@ -6627,20 +6633,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // Add the package's KeySets to the global KeySetManagerService - KeySetManagerService ksms = mSettings.mKeySetManagerService; - try { - ksms.addSigningKeySetToPackageLPw(pkg.packageName, pkg.mSigningKeys); - if (pkg.mKeySetMapping != null) { - ksms.addDefinedKeySetsToPackageLPw(pkg.packageName, pkg.mKeySetMapping); - if (pkg.mUpgradeKeySets != null) { - ksms.addUpgradeKeySetsToPackageLPw(pkg.packageName, pkg.mUpgradeKeySets); - } - } - } catch (NullPointerException e) { - Slog.e(TAG, "Could not add KeySet to " + pkg.packageName, e); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Could not add KeySet to malformed package" + pkg.packageName, e); - } + ksms.addScannedPackageLPw(pkg); int N = pkg.providers.size(); StringBuilder r = null; @@ -11189,7 +11182,7 @@ public class PackageManagerService extends IPackageManager.Stub { KeySetManagerService ksms = mSettings.mKeySetManagerService; for (int i = 0; i < upgradeKeySets.length; i++) { Set<PublicKey> upgradeSet = ksms.getPublicKeysFromKeySetLPr(upgradeKeySets[i]); - if (newPkg.mSigningKeys.containsAll(upgradeSet)) { + if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) { return true; } } |