keystore2 support for app UID migration
- Update migrate_key_namespace to accept specific UIDs for APP domain
source and destination key descriptors
- Add new API to maintenance service to query a list of aliases for
specified app UIDs
Test: atest SharedUserMigrationTest#testDataMigration (in internal)
Bug: 211665859
Change-Id: Ica06a8cd7c3f7b85f58d5953a22231cf7e9a1d7f
diff --git a/keystore2/src/maintenance.rs b/keystore2/src/maintenance.rs
index 57abc26..39958a3 100644
--- a/keystore2/src/maintenance.rs
+++ b/keystore2/src/maintenance.rs
@@ -22,12 +22,14 @@
use crate::globals::{DB, LEGACY_MIGRATOR, SUPER_KEY};
use crate::permission::{KeyPerm, KeystorePerm};
use crate::super_key::UserState;
-use crate::utils::{check_key_permission, check_keystore_permission, watchdog as wd};
+use crate::utils::{
+ check_key_permission, check_keystore_permission, list_key_entries, watchdog as wd,
+};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
IKeyMintDevice::IKeyMintDevice, SecurityLevel::SecurityLevel,
};
use android_security_maintenance::aidl::android::security::maintenance::{
- IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance},
+ IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance, UID_SELF},
UserState::UserState as AidlUserState,
};
use android_security_maintenance::binder::{
@@ -37,6 +39,7 @@
use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
use anyhow::{Context, Result};
use keystore2_crypto::Password;
+use keystore2_selinux as selinux;
/// Reexport Domain for the benefit of DeleteListener
pub use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
@@ -214,46 +217,64 @@
}
fn migrate_key_namespace(source: &KeyDescriptor, destination: &KeyDescriptor) -> Result<()> {
- let caller_uid = ThreadState::get_calling_uid();
let migrate_any_key_permission =
check_keystore_permission(KeystorePerm::MigrateAnyKey).is_ok();
- DB.with(|db| {
- let key_id_guard = match source.domain {
- Domain::APP | Domain::SELINUX | Domain::KEY_ID => {
- let (key_id_guard, _) = LEGACY_MIGRATOR
- .with_try_migrate(source, caller_uid, || {
- db.borrow_mut().load_key_entry(
- source,
- KeyType::Client,
- KeyEntryLoadBits::NONE,
- caller_uid,
- |k, av| {
- if !migrate_any_key_permission {
- check_key_permission(KeyPerm::Use, k, &av)?;
- check_key_permission(KeyPerm::Delete, k, &av)?;
- check_key_permission(KeyPerm::Grant, k, &av)?;
- }
- Ok(())
- },
- )
- })
- .context("In migrate_key_namespace: Failed to load key blob.")?;
- key_id_guard
- }
- _ => {
- return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(concat!(
- "In migrate_key_namespace: ",
- "Source domain must be one of APP, SELINUX, or KEY_ID."
- ))
- }
- };
+ let src_uid = match source.domain {
+ Domain::SELINUX | Domain::KEY_ID => ThreadState::get_calling_uid(),
+ Domain::APP if source.nspace == UID_SELF.into() => ThreadState::get_calling_uid(),
+ Domain::APP if source.nspace != UID_SELF.into() && migrate_any_key_permission => {
+ source.nspace as u32
+ }
+ _ => {
+ return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
+ "In migrate_key_namespace:
+ Source domain must be one of APP, SELINUX, or KEY_ID.",
+ )
+ }
+ };
- db.borrow_mut().migrate_key_namespace(key_id_guard, destination, caller_uid, |k| {
- if !migrate_any_key_permission {
- check_key_permission(KeyPerm::Rebind, k, &None)?;
+ let dest_uid = match destination.domain {
+ Domain::SELINUX => ThreadState::get_calling_uid(),
+ Domain::APP if destination.nspace == UID_SELF.into() => ThreadState::get_calling_uid(),
+ Domain::APP if destination.nspace != UID_SELF.into() && migrate_any_key_permission => {
+ destination.nspace as u32
+ }
+ _ => {
+ return Err(Error::Rc(ResponseCode::INVALID_ARGUMENT)).context(
+ "In migrate_key_namespace:
+ Destination domain must be one of APP or SELINUX.",
+ )
+ }
+ };
+
+ DB.with(|db| {
+ let (key_id_guard, _) = LEGACY_MIGRATOR
+ .with_try_migrate(source, src_uid, || {
+ db.borrow_mut().load_key_entry(
+ source,
+ KeyType::Client,
+ KeyEntryLoadBits::NONE,
+ src_uid,
+ |k, av| {
+ if migrate_any_key_permission {
+ Ok(())
+ } else {
+ check_key_permission(KeyPerm::Use, k, &av)?;
+ check_key_permission(KeyPerm::Delete, k, &av)?;
+ check_key_permission(KeyPerm::Grant, k, &av)
+ }
+ },
+ )
+ })
+ .context("In migrate_key_namespace: Failed to load key blob.")?;
+
+ db.borrow_mut().migrate_key_namespace(key_id_guard, destination, dest_uid, |k| {
+ if migrate_any_key_permission {
+ Ok(())
+ } else {
+ check_key_permission(KeyPerm::Rebind, k, &None)
}
- Ok(())
})
})
}
@@ -266,6 +287,30 @@
Maintenance::call_on_all_security_levels("deleteAllKeys", |dev| dev.deleteAllKeys())
}
+
+ fn list_entries(domain: Domain, nspace: i64) -> Result<Vec<KeyDescriptor>> {
+ let k = match domain {
+ Domain::APP | Domain::SELINUX => KeyDescriptor{domain, nspace, ..Default::default()},
+ _ => return Err(Error::perm()).context(
+ "In list_entries: List entries is only supported for Domain::APP and Domain::SELINUX."
+ ),
+ };
+
+ // The caller has to have either GetInfo for the namespace or List permission
+ check_key_permission(KeyPerm::GetInfo, &k, &None)
+ .or_else(|e| {
+ if Some(&selinux::Error::PermissionDenied)
+ == e.root_cause().downcast_ref::<selinux::Error>()
+ {
+ check_keystore_permission(KeystorePerm::List)
+ } else {
+ Err(e)
+ }
+ })
+ .context("In list_entries: While checking key and keystore permission.")?;
+
+ DB.with(|db| list_key_entries(&mut db.borrow_mut(), domain, nspace))
+ }
}
impl Interface for Maintenance {}
@@ -315,6 +360,11 @@
map_or_log_err(Self::migrate_key_namespace(source, destination), Ok)
}
+ fn listEntries(&self, domain: Domain, namespace: i64) -> BinderResult<Vec<KeyDescriptor>> {
+ let _wp = wd::watch_millis("IKeystoreMaintenance::listEntries", 500);
+ map_or_log_err(Self::list_entries(domain, namespace), Ok)
+ }
+
fn deleteAllKeys(&self) -> BinderResult<()> {
let _wp = wd::watch_millis("IKeystoreMaintenance::deleteAllKeys", 500);
map_or_log_err(Self::delete_all_keys(), Ok)
diff --git a/keystore2/src/service.rs b/keystore2/src/service.rs
index 70f5c71..13723f0 100644
--- a/keystore2/src/service.rs
+++ b/keystore2/src/service.rs
@@ -22,7 +22,7 @@
use crate::security_level::KeystoreSecurityLevel;
use crate::utils::{
check_grant_permission, check_key_permission, check_keystore_permission,
- key_parameters_to_authorizations, watchdog as wd,
+ key_parameters_to_authorizations, list_key_entries, watchdog as wd,
};
use crate::{
database::Uuid,
@@ -286,22 +286,7 @@
Ok(()) => {}
};
- let mut result = LEGACY_MIGRATOR
- .list_uid(k.domain, k.nspace)
- .context("In list_entries: Trying to list legacy keys.")?;
-
- result.append(
- &mut DB
- .with(|db| {
- let mut db = db.borrow_mut();
- db.list(k.domain, k.nspace, KeyType::Client)
- })
- .context("In list_entries: Trying to list keystore database.")?,
- );
-
- result.sort_unstable();
- result.dedup();
- Ok(result)
+ DB.with(|db| list_key_entries(&mut db.borrow_mut(), k.domain, k.nspace))
}
fn delete_key(&self, key: &KeyDescriptor) -> Result<()> {
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index f6d92ee..82e6700 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -18,6 +18,10 @@
use crate::error::{map_binder_status, Error, ErrorCode};
use crate::permission;
use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
+use crate::{
+ database::{KeyType, KeystoreDB},
+ globals::LEGACY_MIGRATOR,
+};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
KeyCharacteristics::KeyCharacteristics, Tag::Tag,
};
@@ -27,9 +31,9 @@
ResponseCode::ResponseCode as ApcResponseCode,
};
use android_system_keystore2::aidl::android::system::keystore2::{
- Authorization::Authorization, KeyDescriptor::KeyDescriptor,
+ Authorization::Authorization, Domain::Domain, KeyDescriptor::KeyDescriptor,
};
-use anyhow::Context;
+use anyhow::{Context, Result};
use binder::{Strong, ThreadState};
use keystore2_apc_compat::{
ApcCompatUiOptions, APC_COMPAT_ERROR_ABORTED, APC_COMPAT_ERROR_CANCELLED,
@@ -199,6 +203,28 @@
rustutils::users::multiuser_get_user_id(uid)
}
+/// List all key aliases for a given domain + namespace.
+pub fn list_key_entries(
+ db: &mut KeystoreDB,
+ domain: Domain,
+ namespace: i64,
+) -> Result<Vec<KeyDescriptor>> {
+ let mut result = Vec::new();
+ result.append(
+ &mut LEGACY_MIGRATOR
+ .list_uid(domain, namespace)
+ .context("In list_key_entries: Trying to list legacy keys.")?,
+ );
+ result.append(
+ &mut db
+ .list(domain, namespace, KeyType::Client)
+ .context("In list_key_entries: Trying to list keystore database.")?,
+ );
+ result.sort_unstable();
+ result.dedup();
+ Ok(result)
+}
+
/// This module provides helpers for simplified use of the watchdog module.
#[cfg(feature = "watchdog")]
pub mod watchdog {