summaryrefslogtreecommitdiff
path: root/keystore2/tests
diff options
context:
space:
mode:
authorRajesh Nyamagoud <nyamagoud@google.com>2022-07-29 00:33:48 +0000
committerRajesh Nyamagoud <nyamagoud@google.com>2022-08-31 18:27:03 +0000
commit01d4cde74ac734b1e7d527f9c30bba82bbc0a7e4 (patch)
tree048d572222550631b9a4826d2b96e0724845d5cb /keystore2/tests
parent6ec53e3489dc7a24b72c5fadeaad60a6c04610d4 (diff)
downloadsecurity-01d4cde74ac734b1e7d527f9c30bba82bbc0a7e4.tar.gz
Adding a test to simulate `OPERATION_BUSY` error from keystore.
The test tries to create a race condition: It creates an operation and starts two threads, each trying to use the operation repeatedly until it gets `OPERATION_BUSY` or finishes successfully. Bug: 194359114 Test: atest keystore2_client_test Change-Id: Ib3549d6bcad4e24bf621960f0f399481bf2da7c7
Diffstat (limited to 'keystore2/tests')
-rw-r--r--keystore2/tests/keystore2_client_operation_tests.rs50
1 files changed, 49 insertions, 1 deletions
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index d8b85f6f..e1102ddc 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -14,12 +14,15 @@
use nix::unistd::{getuid, Gid, Uid};
use rustutils::users::AID_USER_OFFSET;
+use std::thread;
+use std::thread::JoinHandle;
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
};
use android_system_keystore2::aidl::android::system::keystore2::{
- CreateOperationResponse::CreateOperationResponse, Domain::Domain, ResponseCode::ResponseCode,
+ CreateOperationResponse::CreateOperationResponse, Domain::Domain,
+ IKeystoreOperation::IKeystoreOperation, ResponseCode::ResponseCode,
};
use keystore2_test_utils::{
@@ -57,6 +60,25 @@ pub fn create_operations(
.collect()
}
+/// Executes an operation in a thread. Expect an `OPERATION_BUSY` error in case of operation
+/// failure. Returns True if `OPERATION_BUSY` error is encountered otherwise returns false.
+fn perform_op_busy_in_thread(op: binder::Strong<dyn IKeystoreOperation>) -> JoinHandle<bool> {
+ thread::spawn(move || {
+ for _n in 1..1000 {
+ match key_generations::map_ks_error(op.update(b"my message")) {
+ Ok(_) => continue,
+ Err(e) => {
+ assert_eq!(Error::Rc(ResponseCode::OPERATION_BUSY), e);
+ return true;
+ }
+ }
+ }
+ let sig = op.finish(None, None).unwrap();
+ assert!(sig.is_some());
+ false
+ })
+}
+
/// This test verifies that backend service throws BACKEND_BUSY error when all
/// operations slots are full. This test creates operations in child processes and
/// collects the status of operations performed in each child proc and determines
@@ -402,3 +424,29 @@ fn keystore2_forced_op_success_test() {
});
}
}
+
+/// Create an operation and try to use this operation handle in multiple threads to perform
+/// operations. Test should fail to perform an operation with an error response `OPERATION_BUSY`
+/// when multiple threads try to access the operation handle at same time.
+#[test]
+fn keystore2_op_fails_operation_busy() {
+ let op_response = create_signing_operation(
+ ForcedOp(false),
+ KeyPurpose::SIGN,
+ Digest::SHA_2_256,
+ Domain::APP,
+ -1,
+ Some("op_busy_alias_test_key".to_string()),
+ )
+ .unwrap();
+
+ let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+
+ let th_handle_1 = perform_op_busy_in_thread(op.clone());
+ let th_handle_2 = perform_op_busy_in_thread(op);
+
+ let result1 = th_handle_1.join().unwrap();
+ let result2 = th_handle_2.join().unwrap();
+
+ assert!(result1 || result2);
+}