summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author John Wu <topjohnwu@google.com> 2022-01-18 17:44:20 -0800
committer John Wu <topjohnwu@google.com> 2022-01-21 01:36:43 +0000
commit14ce8bc12010a9ef3a96001dad57a88d951abf7e (patch)
treea1d1bb2a78d442ad310ad7f893a237c1010e832e
parent1acb7b93ddbfbca909a3f7ec7aee72df10a94b51 (diff)
Framework support for AndroidKeyStore migration
- Add a new boolean attribute `inheritKeyStoreKeys` to allow apps to indicate whether they want keys to be transferred to the updated app - Call the appropriate KeyStore method to migrate keys from the old namespace to the new one - Clear keys owned by the previous app ID if it is removed Test: atest SharedUserMigrationTest#testKeyMigration Test: atest AndroidPackageTest Bug: 179284822 Change-Id: I321b85b88c150f17709a2270c0cbaf368ca035cc
-rw-r--r--core/api/current.txt1
-rw-r--r--core/res/res/values/attrs_manifest.xml10
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--keystore/java/android/security/KeyStore.java10
-rw-r--r--services/core/java/com/android/server/pm/AppDataHelper.java38
-rw-r--r--services/core/java/com/android/server/pm/DeletePackageHelper.java3
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java11
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java27
-rw-r--r--services/core/java/com/android/server/pm/RemovePackageHelper.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java10
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java15
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java4
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt5
14 files changed, 97 insertions, 48 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 735de5421f16..32a5e62c1c16 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -824,6 +824,7 @@ package android {
field public static final int indicatorRight = 16843022; // 0x101010e
field public static final int indicatorStart = 16843729; // 0x10103d1
field public static final int inflatedId = 16842995; // 0x10100f3
+ field public static final int inheritKeyStoreKeys;
field public static final int inheritShowWhenLocked = 16844188; // 0x101059c
field public static final int initOrder = 16842778; // 0x101001a
field public static final int initialKeyguardLayout = 16843714; // 0x10103c2
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index a5954338910d..3a2fb6e70ba8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -401,6 +401,15 @@
and before. -->
<attr name="sharedUserMaxSdkVersion" format="integer" />
+ <!-- Whether the application should inherit all AndroidKeyStore keys of its shared user
+ group in the case of leaving its shared user ID in an upgrade. If set to false, all
+ AndroidKeyStore keys will remain in the shared user group, and the application will no
+ longer have access to those keys after the upgrade. If set to true, all AndroidKeyStore
+ keys owned by the shared user group will be transferred to the upgraded application;
+ other applications in the shared user group will no longer have access to those keys
+ after the migration. The default value is false if not explicitly set. -->
+ <attr name="inheritKeyStoreKeys" format="boolean" />
+
<!-- Internal version code. This is the number used to determine whether
one version is more recent than another: it has no other meaning than
that higher numbers are more recent. You could use this number to
@@ -1677,6 +1686,7 @@
<attr name="sharedUserId" />
<attr name="sharedUserLabel" />
<attr name="sharedUserMaxSdkVersion" />
+ <attr name="inheritKeyStoreKeys" />
<attr name="installLocation" />
<attr name="isolatedSplits" />
<attr name="isFeatureSplit" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e83f4a66883c..19547b85505c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3256,6 +3256,7 @@
<public name="gameSessionService" />
<public name="localeConfig" />
<public name="showBackground" />
+ <public name="inheritKeyStoreKeys" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index a9543443d3f4..8811a7fec932 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -20,7 +20,6 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.UserHandle;
import android.security.maintenance.UserState;
-import android.system.keystore2.Domain;
/**
* @hide This should not be made public in its present form because it
@@ -120,15 +119,6 @@ public class KeyStore {
}
/**
- * Forwards the request to clear a UID to Keystore 2.0.
- * @hide
- */
- public boolean clearUid(int uid) {
- return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
- }
-
-
- /**
* Add an authentication record to the keystore authorization table.
*
* @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster.
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index a66af3cf7603..f7d0950892d3 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -24,7 +24,6 @@ import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageManager;
-import com.android.server.pm.pkg.SELinuxUtil;
import android.content.pm.UserInfo;
import android.os.CreateAppDataArgs;
import android.os.Environment;
@@ -35,6 +34,9 @@ import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
+import android.security.AndroidKeyStoreMaintenance;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
@@ -46,6 +48,7 @@ import com.android.server.SystemServerInitThreadPool;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.SELinuxUtil;
import dalvik.system.VMRuntime;
@@ -156,8 +159,7 @@ final class AppDataHelper {
* <ul>
* <li>If previousAppId < 0, app data will be migrated to the new app ID
* <li>If previousAppId == 0, no migration will happen and data will be wiped and recreated
- * <li>If previousAppId > 0, it will migrate all data owned by previousAppId
- * to the new app ID
+ * <li>If previousAppId > 0, app data owned by previousAppId will be migrated to the new app ID
* </ul>
*/
private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
@@ -549,6 +551,22 @@ final class AppDataHelper {
return prepareAppDataFuture;
}
+ public void migrateKeyStoreData(int previousAppId, int appId) {
+ for (int userId : mPm.resolveUserIds(UserHandle.USER_ALL)) {
+ int srcUid = UserHandle.getUid(userId, previousAppId);
+ int destUid = UserHandle.getUid(userId, appId);
+ final KeyDescriptor[] keys = AndroidKeyStoreMaintenance.listEntries(Domain.APP, srcUid);
+ if (keys == null) continue;
+ for (final KeyDescriptor key : keys) {
+ KeyDescriptor dest = new KeyDescriptor();
+ dest.domain = Domain.APP;
+ dest.nspace = destUid;
+ dest.alias = key.alias;
+ AndroidKeyStoreMaintenance.migrateKeyNamespace(key, dest);
+ }
+ }
+ }
+
void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
if (pkg == null) {
return;
@@ -633,4 +651,18 @@ final class AppDataHelper {
pkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
return noAppDataProp == null || !noAppDataProp.getBoolean();
}
+
+ /**
+ * Remove entries from the keystore daemon. Will only remove if the {@code appId} is valid.
+ */
+ public void clearKeystoreData(int userId, int appId) {
+ if (appId < 0) {
+ return;
+ }
+
+ for (int realUserId : mPm.resolveUserIds(userId)) {
+ AndroidKeyStoreMaintenance.clearNamespace(
+ Domain.APP, UserHandle.getUid(realUserId, appId));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/DeletePackageHelper.java b/services/core/java/com/android/server/pm/DeletePackageHelper.java
index 9a80a4e558c4..48689a8da335 100644
--- a/services/core/java/com/android/server/pm/DeletePackageHelper.java
+++ b/services/core/java/com/android/server/pm/DeletePackageHelper.java
@@ -485,8 +485,7 @@ final class DeletePackageHelper {
mAppDataHelper.destroyAppDataLIF(pkg, nextUserId,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
}
- PackageManagerService.removeKeystoreDataIfNeeded(mUserManagerInternal, nextUserId,
- ps.getAppId());
+ mAppDataHelper.clearKeystoreData(nextUserId, ps.getAppId());
preferredActivityHelper.clearPackagePreferredActivities(ps.getPackageName(),
nextUserId);
mPm.mDomainVerificationManager.clearPackageForUser(ps.getPackageName(), nextUserId);
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c9478dd30f40..4e17a98af384 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -2246,6 +2246,17 @@ final class InstallPackageHelper {
if (reconciledPkg.mScanResult.needsNewAppId()) {
// Only set previousAppId if the app is migrating out of shared UID
previousAppId = reconciledPkg.mScanResult.mPreviousAppId;
+
+ if (pkg.shouldInheritKeyStoreKeys()) {
+ // Migrate keystore data
+ mAppDataHelper.migrateKeyStoreData(
+ previousAppId, reconciledPkg.mPkgSetting.getAppId());
+ }
+
+ if (reconciledPkg.mInstallResult.mRemovedInfo.mRemovedAppId == previousAppId) {
+ // If the previous app ID is removed, clear the keys
+ mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, previousAppId);
+ }
}
mAppDataHelper.prepareAppDataPostCommitLIF(pkg, previousAppId);
if (reconciledPkg.mPrepareResult.mClearCodeCache) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 13f91e0dca62..88b707d30940 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -167,7 +167,6 @@ import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
-import android.security.KeyStore;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -5445,7 +5444,7 @@ public class PackageManagerService extends IPackageManager.Stub
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
final int appId = UserHandle.getAppId(pkg.getUid());
- removeKeystoreDataIfNeeded(mInjector.getUserManagerInternal(), userId, appId);
+ mAppDataHelper.clearKeystoreData(userId, appId);
UserManagerInternal umInternal = mInjector.getUserManagerInternal();
StorageManagerInternal smInternal = mInjector.getLocalService(StorageManagerInternal.class);
@@ -5518,30 +5517,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- /**
- * Remove entries from the keystore daemon. Will only remove it if the
- * {@code appId} is valid.
- */
- static void removeKeystoreDataIfNeeded(UserManagerInternal um, @UserIdInt int userId,
- @AppIdInt int appId) {
- if (appId < 0) {
- return;
- }
-
- final KeyStore keyStore = KeyStore.getInstance();
- if (keyStore != null) {
- if (userId == UserHandle.USER_ALL) {
- for (final int individual : um.getUserIds()) {
- keyStore.clearUid(UserHandle.getUid(individual, appId));
- }
- } else {
- keyStore.clearUid(UserHandle.getUid(userId, appId));
- }
- } else {
- Slog.w(TAG, "Could not contact keystore to clear entries for app id " + appId);
- }
- }
-
@Override
public void deleteApplicationCacheFiles(final String packageName,
final IPackageDataObserver observer) {
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index b0e03403b653..7e898cbe86b0 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -29,7 +29,6 @@ import static com.android.server.pm.PackageManagerService.TAG;
import android.annotation.NonNull;
import android.content.pm.PackageManager;
-import com.android.server.pm.pkg.component.ParsedInstrumentation;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
import android.util.Log;
@@ -43,6 +42,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
import java.io.File;
import java.util.Collections;
@@ -330,8 +330,7 @@ final class RemovePackageHelper {
if (removedAppId != -1) {
// A user ID was deleted here. Go through all users and remove it
// from KeyStore.
- mPm.removeKeystoreDataIfNeeded(
- mUserManagerInternal, UserHandle.USER_ALL, removedAppId);
+ mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, removedAppId);
}
}
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index 18a6435d17c8..52d9b7a3abc1 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -26,6 +26,10 @@ import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager.Property;
import android.content.pm.SigningDetails;
+import android.os.Bundle;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
import com.android.server.pm.pkg.component.ParsedActivity;
import com.android.server.pm.pkg.component.ParsedApexSystemService;
import com.android.server.pm.pkg.component.ParsedAttribution;
@@ -37,9 +41,6 @@ import com.android.server.pm.pkg.component.ParsedProcess;
import com.android.server.pm.pkg.component.ParsedProvider;
import com.android.server.pm.pkg.component.ParsedService;
import com.android.server.pm.pkg.component.ParsedUsesPermission;
-import android.os.Bundle;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
import java.security.PublicKey;
import java.util.Map;
@@ -286,6 +287,9 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setInstallLocation(int installLocation);
+ /** @see R#styleable.AndroidManifest_inheritKeyStoreKeys */
+ ParsingPackage setInheritKeyStoreKeys(boolean inheritKeyStoreKeys);
+
ParsingPackage setLabelRes(int labelRes);
ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index c4de862bccd9..1f21938fc706 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -492,6 +492,10 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
ENABLED,
DISALLOW_PROFILING,
REQUEST_FOREGROUND_SERVICE_EXEMPTION,
+ ATTRIBUTIONS_ARE_USER_VISIBLE,
+ RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED,
+ SDK_LIBRARY,
+ INHERIT_KEYSTORE_KEYS,
})
public @interface Values {}
private static final long EXTERNAL_STORAGE = 1L;
@@ -544,6 +548,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
private static final long ATTRIBUTIONS_ARE_USER_VISIBLE = 1L << 47;
private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48;
private static final long SDK_LIBRARY = 1L << 49;
+ private static final long INHERIT_KEYSTORE_KEYS = 1L << 50;
}
private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2371,6 +2376,11 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
+ public boolean shouldInheritKeyStoreKeys() {
+ return getBoolean(Booleans.INHERIT_KEYSTORE_KEYS);
+ }
+
+ @Override
public ParsingPackageImpl setBaseRevisionCode(int value) {
baseRevisionCode = value;
return this;
@@ -2514,6 +2524,11 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
+ public ParsingPackageImpl setInheritKeyStoreKeys(boolean value) {
+ return setBoolean(Booleans.INHERIT_KEYSTORE_KEYS, value);
+ }
+
+ @Override
public ParsingPackageImpl setLabelRes(int value) {
labelRes = value;
return this;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 149711287f32..4b659a14418f 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -350,4 +350,9 @@ public interface ParsingPackageRead extends PkgWithoutStateAppInfo, PkgWithoutSt
* @see R.styleable#AndroidManifestApplication_localeConfig
*/
int getLocaleConfigRes();
+
+ /**
+ * @see R.styleable#AndroidManifest_inheritKeyStoreKeys
+ */
+ boolean shouldInheritKeyStoreKeys();
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 1ce01f633791..bf7c55f0f59e 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -868,7 +868,9 @@ public class ParsingPackageUtils {
.setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
R.styleable.AndroidManifest_targetSandboxVersion, sa))
/* Set the global "on SD card" flag */
- .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);
+ .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0)
+ .setInheritKeyStoreKeys(bool(false,
+ R.styleable.AndroidManifest_inheritKeyStoreKeys, sa));
boolean foundApp = false;
final int depth = parser.getDepth();
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index a0f3bbf928ab..cc663d955612 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -503,6 +503,11 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
PackageManager.Property::getString
)
}
+ ),
+ getSetByValue(
+ AndroidPackage::shouldInheritKeyStoreKeys,
+ ParsingPackage::setInheritKeyStoreKeys,
+ true
)
)