Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14ce8bc1 authored by John Wu's avatar John Wu
Browse files

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
parent 1acb7b93
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -824,6 +824,7 @@ package android {
    field public static final int indicatorRight = 16843022; // 0x101010e
    field public static final int indicatorRight = 16843022; // 0x101010e
    field public static final int indicatorStart = 16843729; // 0x10103d1
    field public static final int indicatorStart = 16843729; // 0x10103d1
    field public static final int inflatedId = 16842995; // 0x10100f3
    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 inheritShowWhenLocked = 16844188; // 0x101059c
    field public static final int initOrder = 16842778; // 0x101001a
    field public static final int initOrder = 16842778; // 0x101001a
    field public static final int initialKeyguardLayout = 16843714; // 0x10103c2
    field public static final int initialKeyguardLayout = 16843714; // 0x10103c2
+10 −0
Original line number Original line Diff line number Diff line
@@ -401,6 +401,15 @@
         and before. -->
         and before. -->
    <attr name="sharedUserMaxSdkVersion" format="integer" />
    <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
    <!-- Internal version code.  This is the number used to determine whether
         one version is more recent than another: it has no other meaning than
         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
         that higher numbers are more recent.  You could use this number to
@@ -1677,6 +1686,7 @@
        <attr name="sharedUserId" />
        <attr name="sharedUserId" />
        <attr name="sharedUserLabel" />
        <attr name="sharedUserLabel" />
        <attr name="sharedUserMaxSdkVersion" />
        <attr name="sharedUserMaxSdkVersion" />
        <attr name="inheritKeyStoreKeys" />
        <attr name="installLocation" />
        <attr name="installLocation" />
        <attr name="isolatedSplits" />
        <attr name="isolatedSplits" />
        <attr name="isFeatureSplit" />
        <attr name="isFeatureSplit" />
+1 −0
Original line number Original line Diff line number Diff line
@@ -3256,6 +3256,7 @@
    <public name="gameSessionService" />
    <public name="gameSessionService" />
    <public name="localeConfig" />
    <public name="localeConfig" />
    <public name="showBackground" />
    <public name="showBackground" />
    <public name="inheritKeyStoreKeys" />
  </staging-public-group>
  </staging-public-group>


  <staging-public-group type="id" first-id="0x01de0000">
  <staging-public-group type="id" first-id="0x01de0000">
+0 −10
Original line number Original line Diff line number Diff line
@@ -20,7 +20,6 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Build;
import android.os.UserHandle;
import android.os.UserHandle;
import android.security.maintenance.UserState;
import android.security.maintenance.UserState;
import android.system.keystore2.Domain;


/**
/**
 * @hide This should not be made public in its present form because it
 * @hide This should not be made public in its present form because it
@@ -119,15 +118,6 @@ public class KeyStore {
        return true;
        return true;
    }
    }


    /**
     * 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.
     * Add an authentication record to the keystore authorization table.
     *
     *
+35 −3
Original line number Original line Diff line number Diff line
@@ -24,7 +24,6 @@ import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import com.android.server.pm.pkg.SELinuxUtil;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo;
import android.os.CreateAppDataArgs;
import android.os.CreateAppDataArgs;
import android.os.Environment;
import android.os.Environment;
@@ -35,6 +34,9 @@ import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
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.text.TextUtils;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
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.dex.ArtManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.pkg.SELinuxUtil;


import dalvik.system.VMRuntime;
import dalvik.system.VMRuntime;


@@ -156,8 +159,7 @@ final class AppDataHelper {
     * <ul>
     * <ul>
     * <li>If previousAppId < 0, app data will be migrated to the new app ID
     * <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, no migration will happen and data will be wiped and recreated
     * <li>If previousAppId > 0, it will migrate all data owned by previousAppId
     * <li>If previousAppId > 0, app data owned by previousAppId will be migrated to the new app ID
     *     to the new app ID
     * </ul>
     * </ul>
     */
     */
    private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
    private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
@@ -549,6 +551,22 @@ final class AppDataHelper {
        return prepareAppDataFuture;
        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) {
    void clearAppDataLIF(AndroidPackage pkg, int userId, int flags) {
        if (pkg == null) {
        if (pkg == null) {
            return;
            return;
@@ -633,4 +651,18 @@ final class AppDataHelper {
                pkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
                pkg.getProperties().get(PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
        return noAppDataProp == null || !noAppDataProp.getBoolean();
        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));
        }
    }
}
}
Loading