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)