Snap for 13197820 from 280768f91f97f10d9198e8ce42b8a1abee89397e to 25Q2-release

Change-Id: I18aa2c80302f5759e979719b2d5d2677eefd1df7
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index aacaa92..8f5617f 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -2528,7 +2528,19 @@
                 );",
                 params![domain.0, namespace, KeyType::Client],
             )
-            .context("Trying to delete grants.")?;
+            .context(format!(
+                "Trying to delete grants issued for keys in domain {:?} and namespace {:?}.",
+                domain.0, namespace
+            ))?;
+            if domain == Domain::APP {
+                // Keystore uses the UID instead of the namespace argument for Domain::APP, so we
+                // just need to delete rows where grantee == namespace.
+                tx.execute("DELETE FROM persistent.grant WHERE grantee = ?;", params![namespace])
+                    .context(format!(
+                    "Trying to delete received grants for domain {:?} and namespace {:?}.",
+                    domain.0, namespace
+                ))?;
+            }
             tx.execute(
                 "DELETE FROM persistent.keyentry
                  WHERE domain = ? AND namespace = ? AND key_type = ?;",
diff --git a/keystore2/src/database/tests.rs b/keystore2/src/database/tests.rs
index 7482a1c..fdcf254 100644
--- a/keystore2/src/database/tests.rs
+++ b/keystore2/src/database/tests.rs
@@ -2126,6 +2126,72 @@
     Ok(())
 }
 
+#[test]
+fn test_unbind_keys_for_namespace_removes_received_grants() -> Result<()> {
+    const USER_ID_1: u32 = 1;
+    const APPLICATION_ID_1: u32 = 11;
+    const APPLICATION_ID_2: u32 = 22;
+    const UID_1_FOR_USER_ID_1: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID_1;
+    const UID_2_FOR_USER_ID_1: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID_2;
+
+    // Check that grants are removed for Domain::APP.
+    {
+        let mut db = new_test_db()?;
+
+        // Pretend two application IDs for user ID 1 were granted access to 1 key each.
+        db.conn.execute(
+            &format!(
+                "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
+                VALUES (1, {UID_1_FOR_USER_ID_1}, 111, 222), (2, {UID_2_FOR_USER_ID_1}, 333, 444);"
+            ),
+            [],
+        )?;
+        // Keystore uses the UID as the namespace for Domain::APP keys.
+        db.unbind_keys_for_namespace(Domain::APP, UID_1_FOR_USER_ID_1.into())?;
+
+        let mut stmt = db.conn.prepare("SELECT id, grantee FROM persistent.grant")?;
+        let mut rows =
+            stmt.query_map::<(i64, u32), _, _>([], |row| Ok((row.get(0)?, row.get(1)?)))?;
+
+        // The row for the grant to the namespace that was cleared (UID_1_FOR_USER_ID_1) should be
+        // deleted. The other row should be untouched.
+        let r = rows.next().unwrap().unwrap();
+        assert_eq!(r, (2, UID_2_FOR_USER_ID_1));
+        assert!(rows.next().is_none());
+    }
+
+    // Check that grants aren't removed for Domain::SELINUX.
+    {
+        let mut db = new_test_db()?;
+
+        // Pretend two application IDs for user ID 1 were granted access to 1 key each.
+        db.conn.execute(
+            &format!(
+                "INSERT INTO persistent.grant (id, grantee, keyentryid, access_vector)
+                VALUES (1, {UID_1_FOR_USER_ID_1}, 111, 222), (2, {UID_2_FOR_USER_ID_1}, 333, 444);"
+            ),
+            [],
+        )?;
+        // Keystore uses the UID as the namespace for Domain::APP keys. Here we're passing in
+        // Domain::SELINUX, but still pass the UID as the "namespace" argument to make sure the
+        // code's logic is correct.
+        db.unbind_keys_for_namespace(Domain::SELINUX, UID_1_FOR_USER_ID_1.into())?;
+
+        let mut stmt = db.conn.prepare("SELECT id, grantee FROM persistent.grant")?;
+        let mut rows =
+            stmt.query_map::<(i64, u32), _, _>([], |row| Ok((row.get(0)?, row.get(1)?)))?;
+
+        // Both rows should still be present.
+        let r = rows.next().unwrap().unwrap();
+        assert_eq!(r, (1, UID_1_FOR_USER_ID_1));
+        let r = rows.next().unwrap().unwrap();
+        assert_eq!(r, (2, UID_2_FOR_USER_ID_1));
+        assert!(rows.next().is_none());
+    }
+
+    Ok(())
+}
+
 fn app_key_exists(db: &mut KeystoreDB, nspace: i64, alias: &str) -> Result<bool> {
     db.key_exists(Domain::APP, nspace, alias, KeyType::Client)
 }
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
index 2494e81..87d5f4d 100644
--- a/keystore2/tests/keystore2_client_grant_key_tests.rs
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -713,6 +713,117 @@
     unsafe { run_as::run_as_root(remove_grantee_user_id_fn) };
 }
 
+/// Grant a key to a UID (user ID A + app B) then clear the namespace for user ID A + app B. Check
+/// that the key can't be loaded by that UID (which would be the UID used if another app were to be
+/// installed for user ID A with the same application ID B).
+#[test]
+fn grant_removed_when_grantee_app_uninstalled() {
+    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 GRANTEE_USER_ID: u32 = 99;
+    const GRANTEE_APPLICATION_ID: u32 = 10001;
+    static GRANTEE_UID: u32 = GRANTEE_USER_ID * AID_USER_OFFSET + GRANTEE_APPLICATION_ID;
+    static GRANTEE_GID: u32 = GRANTEE_UID;
+
+    // Add a new user.
+    let create_grantee_user_id_fn = || {
+        let maint = get_maintenance();
+        maint.onUserAdded(GRANTEE_USER_ID.try_into().unwrap()).expect("failed to add user");
+    };
+
+    // 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_root(create_grantee_user_id_fn) };
+
+    // Child function to generate a key and grant it to GRANTEE_UID 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) };
+
+    // Clear the app's namespace, which is what happens when an app is uninstalled. Exercising the
+    // full app uninstallation "flow" isn't possible from a Keystore VTS test since we'd need to
+    // exercise the Java code that calls into the Keystore service. So, we can only test the
+    // entrypoint that we know gets triggered during app uninstallation based on the code's control
+    // flow.
+    let clear_grantee_uid_namespace_fn = || {
+        let maint = get_maintenance();
+        maint
+            .clearNamespace(Domain::APP, GRANTEE_UID.try_into().unwrap())
+            .expect("failed to clear namespace");
+    };
+
+    // 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_root(clear_grantee_uid_namespace_fn) };
+
+    // The same context identified by <uid, grant_nspace> not longer has access to the above granted
+    // key. This would be the context if a new app were installed and assigned the same app ID.
+    let new_grantee_fn = move || {
+        // Check that the key cannot be accessed via grant (i.e. KeyDescriptor with Domain::GRANT).
+        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());
+
+        // Check that the key also cannot be accessed via key ID (i.e. KeyDescriptor with
+        // Domain::KEY_ID) if the second context somehow gets a hold of it.
+        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(GRANTEE_UID, GRANTEE_GID, new_grantee_fn) };
+
+    // Clean up: remove grantee user.
+    let remove_grantee_user_id_fn = || {
+        let maint = get_maintenance();
+        maint.onUserRemoved(GRANTEE_USER_ID.try_into().unwrap()).expect("failed to remove user");
+    };
+
+    // 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_root(remove_grantee_user_id_fn) };
+}
+
 /// 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]