summaryrefslogtreecommitdiffstats
path: root/services/core
diff options
context:
space:
mode:
authordcashman <dcashman@google.com>2015-06-03 14:46:47 -0700
committerdcashman <dcashman@google.com>2015-06-15 17:14:54 -0700
commit87f794f0bf8b53d6c983968f398c4bde4cb6a014 (patch)
tree5a40a1d1e300edb43acf69a27291752648067b6a /services/core
parent31104fbb7e109e9fe34a09878e4901761fa39f5d (diff)
downloadframeworks_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.java118
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java33
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;
}
}