Snap for 12616459 from b1e92b76f36426a2b1f99f8466a4d7ff659d0695 to 25Q1-release
Change-Id: Ie2ef4fb592e6b291a7a97ce29f8885b4a9116fb2
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 7bf17b5..023774f 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -282,12 +282,19 @@
/// SELinux keystore key backend, and the result is used
/// as target context.
pub fn check_grant_permission(
+ caller_uid: u32,
caller_ctx: &CStr,
access_vec: KeyPermSet,
key: &KeyDescriptor,
) -> anyhow::Result<()> {
let target_context = match key.domain {
- Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
+ Domain::APP => {
+ if caller_uid as i64 != key.nspace {
+ return Err(selinux::Error::perm())
+ .context("Trying to access key without ownership.");
+ }
+ getcon().context("check_grant_permission: getcon failed.")?
+ }
Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
.context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
_ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
diff --git a/keystore2/src/permission/tests.rs b/keystore2/src/permission/tests.rs
index c9aebfe..68c9b74 100644
--- a/keystore2/src/permission/tests.rs
+++ b/keystore2/src/permission/tests.rs
@@ -135,11 +135,11 @@
fn check_grant_permission_app() -> Result<()> {
let system_server_ctx = Context::new("u:r:system_server:s0")?;
let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
- check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
+ check_grant_permission(0, &system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
.expect("Grant permission check failed.");
// attempts to grant the grant permission must always fail even when privileged.
- assert_perm_failed!(check_grant_permission(&system_server_ctx, KeyPerm::Grant.into(), &key));
+ assert_perm_failed!(check_grant_permission(0, &system_server_ctx, KeyPerm::Grant.into(), &key));
Ok(())
}
@@ -153,12 +153,12 @@
blob: None,
};
if is_su {
- assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
+ assert!(check_grant_permission(0, &sctx, NOT_GRANT_PERMS, &key).is_ok());
// attempts to grant the grant permission must always fail even when privileged.
- assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::Grant.into(), &key));
+ assert_perm_failed!(check_grant_permission(0, &sctx, KeyPerm::Grant.into(), &key));
} else {
// unprivileged grant attempts always fail. shell does not have the grant permission.
- assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
+ assert_perm_failed!(check_grant_permission(0, &sctx, UNPRIV_PERMS, &key));
}
Ok(())
}
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 2b69d1e..c6dc11e 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -80,6 +80,7 @@
pub fn check_grant_permission(access_vec: KeyPermSet, key: &KeyDescriptor) -> anyhow::Result<()> {
ThreadState::with_calling_sid(|calling_sid| {
permission::check_grant_permission(
+ ThreadState::get_calling_uid(),
calling_sid
.ok_or_else(Error::sys)
.context(ks_err!("Cannot check permission without calling_sid."))?,
diff --git a/keystore2/tests/keystore2_client_authorizations_tests.rs b/keystore2/tests/keystore2_client_authorizations_tests.rs
index bd9dab9..504e6ab 100644
--- a/keystore2/tests/keystore2_client_authorizations_tests.rs
+++ b/keystore2/tests/keystore2_client_authorizations_tests.rs
@@ -472,6 +472,13 @@
#[test]
fn keystore2_gen_key_auth_max_uses_per_boot() {
let sl = SecLevel::tee();
+ if sl.is_keymaster() {
+ // Older devices with Keymaster implementation may use the key during generateKey to export
+ // the generated public key (EC Key), leading to an unnecessary increment of the
+ // key-associated counter. This can cause the test to fail, so skipping this test on older
+ // devices to avoid test failure.
+ return;
+ }
const MAX_USES_COUNT: i32 = 3;
let gen_params = authorizations::AuthSetBuilder::new()
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
index 83d9753..c171ab1 100644
--- a/keystore2/tests/keystore2_client_grant_key_tests.rs
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -204,11 +204,143 @@
unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
}
+/// Grant an SELINUX key to the user (grantee) with just `GET_INFO` key permissions. Verify whether
+/// grantee can succeed in loading the granted key and try to perform simple operation using this
+/// granted key.
+#[test]
+fn grant_selinux_key_get_info_only() {
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10001;
+ static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static GRANTEE_GID: u32 = GRANTEE_UID;
+
+ // Generate a key and grant it to a user with (just) GET_INFO key permissions.
+ let grantor_fn = || {
+ let access_vector = KeyPermission::GET_INFO.0;
+ let grant_key = generate_and_grant_selinux_key(GRANTEE_UID, access_vector).unwrap();
+
+ assert_eq!(grant_key.domain, Domain::GRANT);
+
+ grant_key.nspace
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder on the main thread.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
+ // In grantee context load the key and try to perform crypto operation.
+ let grantee_fn = move || {
+ let sl = SecLevel::tee();
+
+ // Load the granted key.
+ let key_entry_response = get_granted_key(&sl.keystore2, grant_key_nspace)
+ .expect("failed to get info for granted key");
+
+ // Attempt to perform sample crypto operation using granted key, now identified by <KEY_ID,
+ // key_id>.
+ let result = map_ks_error(
+ sl.binder.createOperation(
+ &key_entry_response.metadata.key,
+ &authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::SIGN)
+ .digest(Digest::SHA_2_256),
+ false,
+ ),
+ );
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+
+ // Try to delete the key using a <GRANT, grant_id> descriptor.
+ let result =
+ map_ks_error(sl.keystore2.deleteKey(&granted_key_descriptor(grant_key_nspace)));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+
+ // Try to delete the key using a <KEY_ID, key_id> descriptor.
+ let result = map_ks_error(sl.keystore2.deleteKey(&key_entry_response.metadata.key));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder on the main thread.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+}
+
+/// Grant an APP key to the user (grantee) with just `GET_INFO` key permissions. Verify whether
+/// grantee can succeed in loading the granted key and try to perform simple operation using this
+/// granted key.
+#[test]
+fn grant_app_key_get_info_only() {
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10001;
+ static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static GRANTEE_GID: u32 = GRANTEE_UID;
+ static ALIAS: &str = "ks_grant_key_info_only";
+
+ // Generate a key and grant it to a user with (just) GET_INFO key permissions.
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let access_vector = KeyPermission::GET_INFO.0;
+ let mut grant_keys = generate_ec_key_and_grant_to_users(
+ &sl,
+ Some(ALIAS.to_string()),
+ vec![GRANTEE_UID.try_into().unwrap()],
+ access_vector,
+ )
+ .unwrap();
+
+ grant_keys.remove(0)
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder on the main thread.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
+ // In grantee context load the key and try to perform crypto operation.
+ let grantee_fn = move || {
+ let sl = SecLevel::tee();
+
+ // Load the granted key.
+ let key_entry_response = get_granted_key(&sl.keystore2, grant_key_nspace)
+ .expect("failed to get info for granted key");
+
+ // Attempt to perform sample crypto operation using granted key, now identified by <KEY_ID,
+ // key_id>.
+ let result = map_ks_error(
+ sl.binder.createOperation(
+ &key_entry_response.metadata.key,
+ &authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::SIGN)
+ .digest(Digest::SHA_2_256),
+ false,
+ ),
+ );
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+
+ // Try to delete the key using a <GRANT, grant_id> descriptor.
+ let result =
+ map_ks_error(sl.keystore2.deleteKey(&granted_key_descriptor(grant_key_nspace)));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+
+ // Try to delete the key using a <KEY_ID, key_id> descriptor.
+ let result = map_ks_error(sl.keystore2.deleteKey(&key_entry_response.metadata.key));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder on the main thread.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+}
+
/// Grant an APP key to the user with DELETE access. In grantee context load the key and delete it.
/// Verify that grantee should succeed in deleting the granted key and in grantor context test
/// should fail to find the key with error response `KEY_NOT_FOUND`.
#[test]
-fn grant_delete_key_success() {
+fn grant_app_key_delete_success() {
const USER_ID: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -267,8 +399,12 @@
/// user from grantee context. Test should make sure second grantee should not have a access to
/// granted key.
#[test]
-#[ignore]
-fn grant_granted_key_fails() {
+fn grant_granted_app_key_fails() {
+ const GRANTOR_USER_ID: u32 = 97;
+ const GRANTOR_APPLICATION_ID: u32 = 10003;
+ static GRANTOR_UID: u32 = GRANTOR_USER_ID * AID_USER_OFFSET + GRANTOR_APPLICATION_ID;
+ static GRANTOR_GID: u32 = GRANTOR_UID;
+
const USER_ID: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -296,15 +432,24 @@
};
// Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
// `--test-threads=1`), and nothing yet done with binder.
- let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+ let grant_key_nspace = unsafe { run_as::run_as_app(GRANTOR_UID, GRANTOR_GID, grantor_fn) };
// Grantee context, load the granted key and try to grant it to `SEC_GRANTEE_UID` grantee.
let grantee_fn = move || {
let keystore2 = get_keystore_service();
let access_vector = KeyPermission::GET_INFO.0;
- let key_entry_response = get_granted_key(&keystore2, grant_key_nspace).unwrap();
+ // Try to grant when identifying the key with <GRANT, grant_nspace>.
+ let result = map_ks_error(keystore2.grant(
+ &granted_key_descriptor(grant_key_nspace),
+ SEC_GRANTEE_UID.try_into().unwrap(),
+ access_vector,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::SYSTEM_ERROR), result.unwrap_err());
+ // Load the key info and try to grant when identifying the key with <KEY_ID, keyid>.
+ let key_entry_response = get_granted_key(&keystore2, grant_key_nspace).unwrap();
let result = map_ks_error(keystore2.grant(
&key_entry_response.metadata.key,
SEC_GRANTEE_UID.try_into().unwrap(),
@@ -331,11 +476,88 @@
unsafe { run_as::run_as_app(SEC_GRANTEE_UID, SEC_GRANTEE_GID, grantee2_fn) };
}
+/// Grant an APP key to one user, from a normal user. Check that grantee context can load the
+/// granted key, but that a second unrelated context cannot.
+#[test]
+fn grant_app_key_only_to_grantee() {
+ const GRANTOR_USER_ID: u32 = 97;
+ const GRANTOR_APPLICATION_ID: u32 = 10003;
+ static GRANTOR_UID: u32 = GRANTOR_USER_ID * AID_USER_OFFSET + GRANTOR_APPLICATION_ID;
+ static GRANTOR_GID: u32 = GRANTOR_UID;
+
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10001;
+ static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static GRANTEE_GID: u32 = GRANTEE_UID;
+
+ const SEC_USER_ID: u32 = 98;
+ const SEC_APPLICATION_ID: u32 = 10001;
+ static SEC_GRANTEE_UID: u32 = SEC_USER_ID * AID_USER_OFFSET + SEC_APPLICATION_ID;
+ static SEC_GRANTEE_GID: u32 = SEC_GRANTEE_UID;
+
+ // Child function to generate a key and grant it to a user with `GET_INFO` permission.
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let access_vector = KeyPermission::GET_INFO.0;
+ let alias = format!("ks_grant_single_{}", getuid());
+ let mut grant_keys = generate_ec_key_and_grant_to_users(
+ &sl,
+ Some(alias),
+ vec![GRANTEE_UID.try_into().unwrap()],
+ access_vector,
+ )
+ .unwrap();
+
+ grant_keys.remove(0)
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder on the main thread.
+ let grant_key_nspace = unsafe { run_as::run_as_app(GRANTOR_UID, GRANTOR_GID, grantor_fn) };
+
+ // Child function for the grantee context: can load the granted key.
+ let grantee_fn = move || {
+ let keystore2 = get_keystore_service();
+ let rsp = get_granted_key(&keystore2, grant_key_nspace).expect("failed to get granted key");
+
+ // Return the underlying key ID to simulate an ID leak.
+ assert_eq!(rsp.metadata.key.domain, Domain::KEY_ID);
+ rsp.metadata.key.nspace
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder on the main thread.
+ let key_id = unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+
+ // Second context does not have access to the above granted key, because it's identified
+ // by <uid, grant_nspace> and the implicit uid value is different. Also, even if the
+ // second context gets hold of the key ID somehow, that also doesn't work.
+ let non_grantee_fn = move || {
+ let keystore2 = get_keystore_service();
+ let result = get_granted_key(&keystore2, grant_key_nspace);
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+
+ let result = map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+ domain: Domain::KEY_ID,
+ nspace: key_id,
+ alias: None,
+ blob: None,
+ }));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder on the main thread.
+ unsafe { run_as::run_as_app(SEC_GRANTEE_UID, SEC_GRANTEE_GID, non_grantee_fn) };
+}
+
/// Try to grant an APP key with `GRANT` access. Keystore2 system shouldn't allow to grant a key
/// with `GRANT` access. Test should fail to grant a key with `PERMISSION_DENIED` error response
/// code.
#[test]
-fn grant_key_with_grant_perm_fails() {
+fn grant_app_key_with_grant_perm_fails() {
let sl = SecLevel::tee();
let access_vector = KeyPermission::GRANT.0;
let alias = format!("ks_grant_access_vec_key_{}", getuid());
@@ -381,7 +603,7 @@
/// Grant an APP key to the user and immediately ungrant the granted key. In grantee context try to load
/// the key. Grantee should fail to load the ungranted key with `KEY_NOT_FOUND` error response.
#[test]
-fn ungrant_key_success() {
+fn ungrant_app_key_success() {
const USER_ID: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -436,7 +658,7 @@
/// key in grantee context. Test should fail to load the granted key in grantee context as the
/// associated key is deleted from grantor context.
#[test]
-fn ungrant_deleted_key_fails() {
+fn ungrant_deleted_app_key_fails() {
const APPLICATION_ID: u32 = 10001;
const USER_ID: u32 = 99;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -507,7 +729,7 @@
/// Grant a key to multiple users. Verify that all grantees should succeed in loading the key and
/// use it for performing an operation successfully.
#[test]
-fn grant_key_to_multi_users_success() {
+fn grant_app_key_to_multi_users_success() {
const APPLICATION_ID: u32 = 10001;
const USER_ID_1: u32 = 99;
static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
@@ -553,7 +775,7 @@
/// use the key and delete it. Try to load the granted key in another grantee context. Test should
/// fail to load the granted key with `KEY_NOT_FOUND` error response.
#[test]
-fn grant_key_to_multi_users_delete_then_key_not_found() {
+fn grant_app_key_to_multi_users_delete_then_key_not_found() {
const USER_ID_1: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;