1 // Copyright 2020, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Implements the android.security.legacykeystore interface.
16 
17 use android_security_legacykeystore::aidl::android::security::legacykeystore::{
18     ILegacyKeystore::BnLegacyKeystore, ILegacyKeystore::ILegacyKeystore,
19     ILegacyKeystore::ERROR_ENTRY_NOT_FOUND, ILegacyKeystore::ERROR_PERMISSION_DENIED,
20     ILegacyKeystore::ERROR_SYSTEM_ERROR, ILegacyKeystore::UID_SELF,
21 };
22 use android_security_legacykeystore::binder::{
23     BinderFeatures, ExceptionCode, Result as BinderResult, Status as BinderStatus, Strong,
24     ThreadState,
25 };
26 use anyhow::{Context, Result};
27 use keystore2::{
28     async_task::AsyncTask, legacy_blob::LegacyBlobLoader, maintenance::DeleteListener,
29     maintenance::Domain, utils::watchdog as wd,
30 };
31 use rusqlite::{
32     params, Connection, OptionalExtension, Transaction, TransactionBehavior, NO_PARAMS,
33 };
34 use std::sync::Arc;
35 use std::{
36     collections::HashSet,
37     path::{Path, PathBuf},
38 };
39 
40 struct DB {
41     conn: Connection,
42 }
43 
44 impl DB {
new(db_file: &Path) -> Result<Self>45     fn new(db_file: &Path) -> Result<Self> {
46         let mut db = Self {
47             conn: Connection::open(db_file).context("Failed to initialize SQLite connection.")?,
48         };
49 
50         db.init_tables().context("Trying to initialize legacy keystore db.")?;
51         Ok(db)
52     }
53 
with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T> where F: Fn(&Transaction) -> Result<T>,54     fn with_transaction<T, F>(&mut self, behavior: TransactionBehavior, f: F) -> Result<T>
55     where
56         F: Fn(&Transaction) -> Result<T>,
57     {
58         loop {
59             match self
60                 .conn
61                 .transaction_with_behavior(behavior)
62                 .context("In with_transaction.")
63                 .and_then(|tx| f(&tx).map(|result| (result, tx)))
64                 .and_then(|(result, tx)| {
65                     tx.commit().context("In with_transaction: Failed to commit transaction.")?;
66                     Ok(result)
67                 }) {
68                 Ok(result) => break Ok(result),
69                 Err(e) => {
70                     if Self::is_locked_error(&e) {
71                         std::thread::sleep(std::time::Duration::from_micros(500));
72                         continue;
73                     } else {
74                         return Err(e).context("In with_transaction.");
75                     }
76                 }
77             }
78         }
79     }
80 
is_locked_error(e: &anyhow::Error) -> bool81     fn is_locked_error(e: &anyhow::Error) -> bool {
82         matches!(
83             e.root_cause().downcast_ref::<rusqlite::ffi::Error>(),
84             Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseBusy, .. })
85                 | Some(rusqlite::ffi::Error { code: rusqlite::ErrorCode::DatabaseLocked, .. })
86         )
87     }
88 
init_tables(&mut self) -> Result<()>89     fn init_tables(&mut self) -> Result<()> {
90         self.with_transaction(TransactionBehavior::Immediate, |tx| {
91             tx.execute(
92                 "CREATE TABLE IF NOT EXISTS profiles (
93                      owner INTEGER,
94                      alias BLOB,
95                      profile BLOB,
96                      UNIQUE(owner, alias));",
97                 NO_PARAMS,
98             )
99             .context("Failed to initialize \"profiles\" table.")?;
100             Ok(())
101         })
102     }
103 
list(&mut self, caller_uid: u32) -> Result<Vec<String>>104     fn list(&mut self, caller_uid: u32) -> Result<Vec<String>> {
105         self.with_transaction(TransactionBehavior::Deferred, |tx| {
106             let mut stmt = tx
107                 .prepare("SELECT alias FROM profiles WHERE owner = ? ORDER BY alias ASC;")
108                 .context("In list: Failed to prepare statement.")?;
109 
110             let aliases = stmt
111                 .query_map(params![caller_uid], |row| row.get(0))?
112                 .collect::<rusqlite::Result<Vec<String>>>()
113                 .context("In list: query_map failed.");
114             aliases
115         })
116     }
117 
put(&mut self, caller_uid: u32, alias: &str, entry: &[u8]) -> Result<()>118     fn put(&mut self, caller_uid: u32, alias: &str, entry: &[u8]) -> Result<()> {
119         self.with_transaction(TransactionBehavior::Immediate, |tx| {
120             tx.execute(
121                 "INSERT OR REPLACE INTO profiles (owner, alias, profile) values (?, ?, ?)",
122                 params![caller_uid, alias, entry,],
123             )
124             .context("In put: Failed to insert or replace.")?;
125             Ok(())
126         })
127     }
128 
get(&mut self, caller_uid: u32, alias: &str) -> Result<Option<Vec<u8>>>129     fn get(&mut self, caller_uid: u32, alias: &str) -> Result<Option<Vec<u8>>> {
130         self.with_transaction(TransactionBehavior::Deferred, |tx| {
131             tx.query_row(
132                 "SELECT profile FROM profiles WHERE owner = ? AND alias = ?;",
133                 params![caller_uid, alias],
134                 |row| row.get(0),
135             )
136             .optional()
137             .context("In get: failed loading entry.")
138         })
139     }
140 
remove(&mut self, caller_uid: u32, alias: &str) -> Result<bool>141     fn remove(&mut self, caller_uid: u32, alias: &str) -> Result<bool> {
142         let removed = self.with_transaction(TransactionBehavior::Immediate, |tx| {
143             tx.execute(
144                 "DELETE FROM profiles WHERE owner = ? AND alias = ?;",
145                 params![caller_uid, alias],
146             )
147             .context("In remove: Failed to delete row.")
148         })?;
149         Ok(removed == 1)
150     }
151 
remove_uid(&mut self, uid: u32) -> Result<()>152     fn remove_uid(&mut self, uid: u32) -> Result<()> {
153         self.with_transaction(TransactionBehavior::Immediate, |tx| {
154             tx.execute("DELETE FROM profiles WHERE owner = ?;", params![uid])
155                 .context("In remove_uid: Failed to delete.")
156         })?;
157         Ok(())
158     }
159 
remove_user(&mut self, user_id: u32) -> Result<()>160     fn remove_user(&mut self, user_id: u32) -> Result<()> {
161         self.with_transaction(TransactionBehavior::Immediate, |tx| {
162             tx.execute(
163                 "DELETE FROM profiles WHERE cast ( ( owner/? ) as int) = ?;",
164                 params![cutils_bindgen::AID_USER_OFFSET, user_id],
165             )
166             .context("In remove_uid: Failed to delete.")
167         })?;
168         Ok(())
169     }
170 }
171 
172 /// This is the main LegacyKeystore error type, it wraps binder exceptions and the
173 /// LegacyKeystore errors.
174 #[derive(Debug, thiserror::Error, PartialEq)]
175 pub enum Error {
176     /// Wraps a LegacyKeystore error code.
177     #[error("Error::Error({0:?})")]
178     Error(i32),
179     /// Wraps a Binder exception code other than a service specific exception.
180     #[error("Binder exception code {0:?}, {1:?}")]
181     Binder(ExceptionCode, i32),
182 }
183 
184 impl Error {
185     /// Short hand for `Error::Error(ERROR_SYSTEM_ERROR)`
sys() -> Self186     pub fn sys() -> Self {
187         Error::Error(ERROR_SYSTEM_ERROR)
188     }
189 
190     /// Short hand for `Error::Error(ERROR_ENTRY_NOT_FOUND)`
not_found() -> Self191     pub fn not_found() -> Self {
192         Error::Error(ERROR_ENTRY_NOT_FOUND)
193     }
194 
195     /// Short hand for `Error::Error(ERROR_PERMISSION_DENIED)`
perm() -> Self196     pub fn perm() -> Self {
197         Error::Error(ERROR_PERMISSION_DENIED)
198     }
199 }
200 
201 /// This function should be used by legacykeystore service calls to translate error conditions
202 /// into service specific exceptions.
203 ///
204 /// All error conditions get logged by this function, except for ERROR_ENTRY_NOT_FOUND error.
205 ///
206 /// `Error::Error(x)` variants get mapped onto a service specific error code of `x`.
207 ///
208 /// All non `Error` error conditions get mapped onto `ERROR_SYSTEM_ERROR`.
209 ///
210 /// `handle_ok` will be called if `result` is `Ok(value)` where `value` will be passed
211 /// as argument to `handle_ok`. `handle_ok` must generate a `BinderResult<T>`, but it
212 /// typically returns Ok(value).
map_or_log_err<T, U, F>(result: Result<U>, handle_ok: F) -> BinderResult<T> where F: FnOnce(U) -> BinderResult<T>,213 fn map_or_log_err<T, U, F>(result: Result<U>, handle_ok: F) -> BinderResult<T>
214 where
215     F: FnOnce(U) -> BinderResult<T>,
216 {
217     result.map_or_else(
218         |e| {
219             let root_cause = e.root_cause();
220             let (rc, log_error) = match root_cause.downcast_ref::<Error>() {
221                 // Make the entry not found errors silent.
222                 Some(Error::Error(ERROR_ENTRY_NOT_FOUND)) => (ERROR_ENTRY_NOT_FOUND, false),
223                 Some(Error::Error(e)) => (*e, true),
224                 Some(Error::Binder(_, _)) | None => (ERROR_SYSTEM_ERROR, true),
225             };
226             if log_error {
227                 log::error!("{:?}", e);
228             }
229             Err(BinderStatus::new_service_specific_error(rc, None))
230         },
231         handle_ok,
232     )
233 }
234 
235 struct LegacyKeystoreDeleteListener {
236     legacy_keystore: Arc<LegacyKeystore>,
237 }
238 
239 impl DeleteListener for LegacyKeystoreDeleteListener {
delete_namespace(&self, domain: Domain, namespace: i64) -> Result<()>240     fn delete_namespace(&self, domain: Domain, namespace: i64) -> Result<()> {
241         self.legacy_keystore.delete_namespace(domain, namespace)
242     }
delete_user(&self, user_id: u32) -> Result<()>243     fn delete_user(&self, user_id: u32) -> Result<()> {
244         self.legacy_keystore.delete_user(user_id)
245     }
246 }
247 
248 /// Implements ILegacyKeystore AIDL interface.
249 pub struct LegacyKeystore {
250     db_path: PathBuf,
251     async_task: AsyncTask,
252 }
253 
254 struct AsyncState {
255     recently_imported: HashSet<(u32, String)>,
256     legacy_loader: LegacyBlobLoader,
257     db_path: PathBuf,
258 }
259 
260 impl LegacyKeystore {
261     /// Note: The filename was chosen before the purpose of this module was extended.
262     ///       It is kept for backward compatibility with early adopters.
263     const LEGACY_KEYSTORE_FILE_NAME: &'static str = "vpnprofilestore.sqlite";
264 
265     const WIFI_NAMESPACE: i64 = 102;
266     const AID_WIFI: u32 = 1010;
267 
268     /// Creates a new LegacyKeystore instance.
new_native_binder( path: &Path, ) -> (Box<dyn DeleteListener + Send + Sync + 'static>, Strong<dyn ILegacyKeystore>)269     pub fn new_native_binder(
270         path: &Path,
271     ) -> (Box<dyn DeleteListener + Send + Sync + 'static>, Strong<dyn ILegacyKeystore>) {
272         let mut db_path = path.to_path_buf();
273         db_path.push(Self::LEGACY_KEYSTORE_FILE_NAME);
274 
275         let legacy_keystore = Arc::new(Self { db_path, async_task: Default::default() });
276         legacy_keystore.init_shelf(path);
277         let service = LegacyKeystoreService { legacy_keystore: legacy_keystore.clone() };
278         (
279             Box::new(LegacyKeystoreDeleteListener { legacy_keystore }),
280             BnLegacyKeystore::new_binder(service, BinderFeatures::default()),
281         )
282     }
283 
open_db(&self) -> Result<DB>284     fn open_db(&self) -> Result<DB> {
285         DB::new(&self.db_path).context("In open_db: Failed to open db.")
286     }
287 
get_effective_uid(uid: i32) -> Result<u32>288     fn get_effective_uid(uid: i32) -> Result<u32> {
289         const AID_SYSTEM: u32 = 1000;
290         let calling_uid = ThreadState::get_calling_uid();
291         let uid = uid as u32;
292 
293         if uid == UID_SELF as u32 || uid == calling_uid {
294             Ok(calling_uid)
295         } else if calling_uid == AID_SYSTEM && uid == Self::AID_WIFI {
296             // The only exception for legacy reasons is allowing SYSTEM to access
297             // the WIFI namespace.
298             // IMPORTANT: If you attempt to add more exceptions, it means you are adding
299             // more callers to this deprecated feature. DON'T!
300             Ok(Self::AID_WIFI)
301         } else {
302             Err(Error::perm()).with_context(|| {
303                 format!("In get_effective_uid: caller: {}, requested uid: {}.", calling_uid, uid)
304             })
305         }
306     }
307 
get(&self, alias: &str, uid: i32) -> Result<Vec<u8>>308     fn get(&self, alias: &str, uid: i32) -> Result<Vec<u8>> {
309         let mut db = self.open_db().context("In get.")?;
310         let uid = Self::get_effective_uid(uid).context("In get.")?;
311 
312         if let Some(entry) = db.get(uid, alias).context("In get: Trying to load entry from DB.")? {
313             return Ok(entry);
314         }
315         if self.get_legacy(uid, alias).context("In get: Trying to migrate legacy blob.")? {
316             // If we were able to migrate a legacy blob try again.
317             if let Some(entry) =
318                 db.get(uid, alias).context("In get: Trying to load entry from DB.")?
319             {
320                 return Ok(entry);
321             }
322         }
323         Err(Error::not_found()).context("In get: No such entry.")
324     }
325 
put(&self, alias: &str, uid: i32, entry: &[u8]) -> Result<()>326     fn put(&self, alias: &str, uid: i32, entry: &[u8]) -> Result<()> {
327         let uid = Self::get_effective_uid(uid).context("In put.")?;
328         // In order to make sure that we don't have stale legacy entries, make sure they are
329         // migrated before replacing them.
330         let _ = self.get_legacy(uid, alias);
331         let mut db = self.open_db().context("In put.")?;
332         db.put(uid, alias, entry).context("In put: Trying to insert entry into DB.")
333     }
334 
remove(&self, alias: &str, uid: i32) -> Result<()>335     fn remove(&self, alias: &str, uid: i32) -> Result<()> {
336         let uid = Self::get_effective_uid(uid).context("In remove.")?;
337         let mut db = self.open_db().context("In remove.")?;
338         // In order to make sure that we don't have stale legacy entries, make sure they are
339         // migrated before removing them.
340         let _ = self.get_legacy(uid, alias);
341         let removed =
342             db.remove(uid, alias).context("In remove: Trying to remove entry from DB.")?;
343         if removed {
344             Ok(())
345         } else {
346             Err(Error::not_found()).context("In remove: No such entry.")
347         }
348     }
349 
delete_namespace(&self, domain: Domain, namespace: i64) -> Result<()>350     fn delete_namespace(&self, domain: Domain, namespace: i64) -> Result<()> {
351         let uid = match domain {
352             Domain::APP => namespace as u32,
353             Domain::SELINUX => {
354                 if namespace == Self::WIFI_NAMESPACE {
355                     // Namespace WIFI gets mapped to AID_WIFI.
356                     Self::AID_WIFI
357                 } else {
358                     // Nothing to do for any other namespace.
359                     return Ok(());
360                 }
361             }
362             _ => return Ok(()),
363         };
364 
365         if let Err(e) = self.bulk_delete_uid(uid) {
366             log::warn!("In LegacyKeystore::delete_namespace: {:?}", e);
367         }
368         let mut db = self.open_db().context("In LegacyKeystore::delete_namespace.")?;
369         db.remove_uid(uid).context("In LegacyKeystore::delete_namespace.")
370     }
371 
delete_user(&self, user_id: u32) -> Result<()>372     fn delete_user(&self, user_id: u32) -> Result<()> {
373         if let Err(e) = self.bulk_delete_user(user_id) {
374             log::warn!("In LegacyKeystore::delete_user: {:?}", e);
375         }
376         let mut db = self.open_db().context("In LegacyKeystore::delete_user.")?;
377         db.remove_user(user_id).context("In LegacyKeystore::delete_user.")
378     }
379 
list(&self, prefix: &str, uid: i32) -> Result<Vec<String>>380     fn list(&self, prefix: &str, uid: i32) -> Result<Vec<String>> {
381         let mut db = self.open_db().context("In list.")?;
382         let uid = Self::get_effective_uid(uid).context("In list.")?;
383         let mut result = self.list_legacy(uid).context("In list.")?;
384         result.append(&mut db.list(uid).context("In list: Trying to get list of entries.")?);
385         result = result.into_iter().filter(|s| s.starts_with(prefix)).collect();
386         result.sort_unstable();
387         result.dedup();
388         Ok(result)
389     }
390 
init_shelf(&self, path: &Path)391     fn init_shelf(&self, path: &Path) {
392         let mut db_path = path.to_path_buf();
393         self.async_task.queue_hi(move |shelf| {
394             let legacy_loader = LegacyBlobLoader::new(&db_path);
395             db_path.push(Self::LEGACY_KEYSTORE_FILE_NAME);
396 
397             shelf.put(AsyncState { legacy_loader, db_path, recently_imported: Default::default() });
398         })
399     }
400 
do_serialized<F, T: Send + 'static>(&self, f: F) -> Result<T> where F: FnOnce(&mut AsyncState) -> Result<T> + Send + 'static,401     fn do_serialized<F, T: Send + 'static>(&self, f: F) -> Result<T>
402     where
403         F: FnOnce(&mut AsyncState) -> Result<T> + Send + 'static,
404     {
405         let (sender, receiver) = std::sync::mpsc::channel::<Result<T>>();
406         self.async_task.queue_hi(move |shelf| {
407             let state = shelf.get_downcast_mut::<AsyncState>().expect("Failed to get shelf.");
408             sender.send(f(state)).expect("Failed to send result.");
409         });
410         receiver.recv().context("In do_serialized: Failed to receive result.")?
411     }
412 
list_legacy(&self, uid: u32) -> Result<Vec<String>>413     fn list_legacy(&self, uid: u32) -> Result<Vec<String>> {
414         self.do_serialized(move |state| {
415             state
416                 .legacy_loader
417                 .list_legacy_keystore_entries_for_uid(uid)
418                 .context("Trying to list legacy keystore entries.")
419         })
420         .context("In list_legacy.")
421     }
422 
get_legacy(&self, uid: u32, alias: &str) -> Result<bool>423     fn get_legacy(&self, uid: u32, alias: &str) -> Result<bool> {
424         let alias = alias.to_string();
425         self.do_serialized(move |state| {
426             if state.recently_imported.contains(&(uid, alias.clone())) {
427                 return Ok(true);
428             }
429             let mut db = DB::new(&state.db_path).context("In open_db: Failed to open db.")?;
430             let migrated =
431                 Self::migrate_one_legacy_entry(uid, &alias, &state.legacy_loader, &mut db)
432                     .context("Trying to migrate legacy keystore entries.")?;
433             if migrated {
434                 state.recently_imported.insert((uid, alias));
435             }
436             Ok(migrated)
437         })
438         .context("In get_legacy.")
439     }
440 
bulk_delete_uid(&self, uid: u32) -> Result<()>441     fn bulk_delete_uid(&self, uid: u32) -> Result<()> {
442         self.do_serialized(move |state| {
443             let entries = state
444                 .legacy_loader
445                 .list_legacy_keystore_entries_for_uid(uid)
446                 .context("In bulk_delete_uid: Trying to list entries.")?;
447             for alias in entries.iter() {
448                 if let Err(e) = state.legacy_loader.remove_legacy_keystore_entry(uid, alias) {
449                     log::warn!("In bulk_delete_uid: Failed to delete legacy entry. {:?}", e);
450                 }
451             }
452             Ok(())
453         })
454     }
455 
bulk_delete_user(&self, user_id: u32) -> Result<()>456     fn bulk_delete_user(&self, user_id: u32) -> Result<()> {
457         self.do_serialized(move |state| {
458             let entries = state
459                 .legacy_loader
460                 .list_legacy_keystore_entries_for_user(user_id)
461                 .context("In bulk_delete_user: Trying to list entries.")?;
462             for (uid, entries) in entries.iter() {
463                 for alias in entries.iter() {
464                     if let Err(e) = state.legacy_loader.remove_legacy_keystore_entry(*uid, alias) {
465                         log::warn!("In bulk_delete_user: Failed to delete legacy entry. {:?}", e);
466                     }
467                 }
468             }
469             Ok(())
470         })
471     }
472 
migrate_one_legacy_entry( uid: u32, alias: &str, legacy_loader: &LegacyBlobLoader, db: &mut DB, ) -> Result<bool>473     fn migrate_one_legacy_entry(
474         uid: u32,
475         alias: &str,
476         legacy_loader: &LegacyBlobLoader,
477         db: &mut DB,
478     ) -> Result<bool> {
479         let blob = legacy_loader
480             .read_legacy_keystore_entry(uid, alias)
481             .context("In migrate_one_legacy_entry: Trying to read legacy keystore entry.")?;
482         if let Some(entry) = blob {
483             db.put(uid, alias, &entry)
484                 .context("In migrate_one_legacy_entry: Trying to insert entry into DB.")?;
485             legacy_loader
486                 .remove_legacy_keystore_entry(uid, alias)
487                 .context("In migrate_one_legacy_entry: Trying to delete legacy keystore entry.")?;
488             Ok(true)
489         } else {
490             Ok(false)
491         }
492     }
493 }
494 
495 struct LegacyKeystoreService {
496     legacy_keystore: Arc<LegacyKeystore>,
497 }
498 
499 impl binder::Interface for LegacyKeystoreService {}
500 
501 impl ILegacyKeystore for LegacyKeystoreService {
get(&self, alias: &str, uid: i32) -> BinderResult<Vec<u8>>502     fn get(&self, alias: &str, uid: i32) -> BinderResult<Vec<u8>> {
503         let _wp = wd::watch_millis("ILegacyKeystore::get", 500);
504         map_or_log_err(self.legacy_keystore.get(alias, uid), Ok)
505     }
put(&self, alias: &str, uid: i32, entry: &[u8]) -> BinderResult<()>506     fn put(&self, alias: &str, uid: i32, entry: &[u8]) -> BinderResult<()> {
507         let _wp = wd::watch_millis("ILegacyKeystore::put", 500);
508         map_or_log_err(self.legacy_keystore.put(alias, uid, entry), Ok)
509     }
remove(&self, alias: &str, uid: i32) -> BinderResult<()>510     fn remove(&self, alias: &str, uid: i32) -> BinderResult<()> {
511         let _wp = wd::watch_millis("ILegacyKeystore::remove", 500);
512         map_or_log_err(self.legacy_keystore.remove(alias, uid), Ok)
513     }
list(&self, prefix: &str, uid: i32) -> BinderResult<Vec<String>>514     fn list(&self, prefix: &str, uid: i32) -> BinderResult<Vec<String>> {
515         let _wp = wd::watch_millis("ILegacyKeystore::list", 500);
516         map_or_log_err(self.legacy_keystore.list(prefix, uid), Ok)
517     }
518 }
519 
520 #[cfg(test)]
521 mod db_test {
522     use super::*;
523     use keystore2_test_utils::TempDir;
524     use std::sync::Arc;
525     use std::thread;
526     use std::time::Duration;
527     use std::time::Instant;
528 
529     static TEST_ALIAS: &str = &"test_alias";
530     static TEST_BLOB1: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
531     static TEST_BLOB2: &[u8] = &[2, 2, 3, 4, 5, 6, 7, 8, 9, 0];
532     static TEST_BLOB3: &[u8] = &[3, 2, 3, 4, 5, 6, 7, 8, 9, 0];
533     static TEST_BLOB4: &[u8] = &[3, 2, 3, 4, 5, 6, 7, 8, 9, 0];
534 
535     #[test]
test_entry_db()536     fn test_entry_db() {
537         let test_dir = TempDir::new("entrydb_test_").expect("Failed to create temp dir.");
538         let mut db = DB::new(&test_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME))
539             .expect("Failed to open database.");
540 
541         // Insert three entries for owner 2.
542         db.put(2, "test1", TEST_BLOB1).expect("Failed to insert test1.");
543         db.put(2, "test2", TEST_BLOB2).expect("Failed to insert test2.");
544         db.put(2, "test3", TEST_BLOB3).expect("Failed to insert test3.");
545 
546         // Check list returns all inserted aliases.
547         assert_eq!(
548             vec!["test1".to_string(), "test2".to_string(), "test3".to_string(),],
549             db.list(2).expect("Failed to list entries.")
550         );
551 
552         // There should be no entries for owner 1.
553         assert_eq!(Vec::<String>::new(), db.list(1).expect("Failed to list entries."));
554 
555         // Check the content of the three entries.
556         assert_eq!(Some(TEST_BLOB1), db.get(2, "test1").expect("Failed to get entry.").as_deref());
557         assert_eq!(Some(TEST_BLOB2), db.get(2, "test2").expect("Failed to get entry.").as_deref());
558         assert_eq!(Some(TEST_BLOB3), db.get(2, "test3").expect("Failed to get entry.").as_deref());
559 
560         // Remove test2 and check and check that it is no longer retrievable.
561         assert!(db.remove(2, "test2").expect("Failed to remove entry."));
562         assert!(db.get(2, "test2").expect("Failed to get entry.").is_none());
563 
564         // test2 should now no longer be in the list.
565         assert_eq!(
566             vec!["test1".to_string(), "test3".to_string(),],
567             db.list(2).expect("Failed to list entries.")
568         );
569 
570         // Put on existing alias replaces it.
571         // Verify test1 is TEST_BLOB1.
572         assert_eq!(Some(TEST_BLOB1), db.get(2, "test1").expect("Failed to get entry.").as_deref());
573         db.put(2, "test1", TEST_BLOB4).expect("Failed to replace test1.");
574         // Verify test1 is TEST_BLOB4.
575         assert_eq!(Some(TEST_BLOB4), db.get(2, "test1").expect("Failed to get entry.").as_deref());
576     }
577 
578     #[test]
test_delete_uid()579     fn test_delete_uid() {
580         let test_dir = TempDir::new("test_delete_uid_").expect("Failed to create temp dir.");
581         let mut db = DB::new(&test_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME))
582             .expect("Failed to open database.");
583 
584         // Insert three entries for owner 2.
585         db.put(2, "test1", TEST_BLOB1).expect("Failed to insert test1.");
586         db.put(2, "test2", TEST_BLOB2).expect("Failed to insert test2.");
587         db.put(3, "test3", TEST_BLOB3).expect("Failed to insert test3.");
588 
589         db.remove_uid(2).expect("Failed to remove uid 2");
590 
591         assert_eq!(Vec::<String>::new(), db.list(2).expect("Failed to list entries."));
592 
593         assert_eq!(vec!["test3".to_string(),], db.list(3).expect("Failed to list entries."));
594     }
595 
596     #[test]
test_delete_user()597     fn test_delete_user() {
598         let test_dir = TempDir::new("test_delete_user_").expect("Failed to create temp dir.");
599         let mut db = DB::new(&test_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME))
600             .expect("Failed to open database.");
601 
602         // Insert three entries for owner 2.
603         db.put(2 + 2 * cutils_bindgen::AID_USER_OFFSET, "test1", TEST_BLOB1)
604             .expect("Failed to insert test1.");
605         db.put(4 + 2 * cutils_bindgen::AID_USER_OFFSET, "test2", TEST_BLOB2)
606             .expect("Failed to insert test2.");
607         db.put(3, "test3", TEST_BLOB3).expect("Failed to insert test3.");
608 
609         db.remove_user(2).expect("Failed to remove user 2");
610 
611         assert_eq!(
612             Vec::<String>::new(),
613             db.list(2 + 2 * cutils_bindgen::AID_USER_OFFSET).expect("Failed to list entries.")
614         );
615 
616         assert_eq!(
617             Vec::<String>::new(),
618             db.list(4 + 2 * cutils_bindgen::AID_USER_OFFSET).expect("Failed to list entries.")
619         );
620 
621         assert_eq!(vec!["test3".to_string(),], db.list(3).expect("Failed to list entries."));
622     }
623 
624     #[test]
concurrent_legacy_keystore_entry_test() -> Result<()>625     fn concurrent_legacy_keystore_entry_test() -> Result<()> {
626         let temp_dir = Arc::new(
627             TempDir::new("concurrent_legacy_keystore_entry_test_")
628                 .expect("Failed to create temp dir."),
629         );
630 
631         let db_path = temp_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME).to_owned();
632 
633         let test_begin = Instant::now();
634 
635         let mut db = DB::new(&db_path).expect("Failed to open database.");
636         const ENTRY_COUNT: u32 = 5000u32;
637         const ENTRY_DB_COUNT: u32 = 5000u32;
638 
639         let mut actual_entry_count = ENTRY_COUNT;
640         // First insert ENTRY_COUNT entries.
641         for count in 0..ENTRY_COUNT {
642             if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
643                 actual_entry_count = count;
644                 break;
645             }
646             let alias = format!("test_alias_{}", count);
647             db.put(1, &alias, TEST_BLOB1).expect("Failed to add entry (1).");
648         }
649 
650         // Insert more keys from a different thread and into a different namespace.
651         let db_path1 = db_path.clone();
652         let handle1 = thread::spawn(move || {
653             let mut db = DB::new(&db_path1).expect("Failed to open database.");
654 
655             for count in 0..actual_entry_count {
656                 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
657                     return;
658                 }
659                 let alias = format!("test_alias_{}", count);
660                 db.put(2, &alias, TEST_BLOB2).expect("Failed to add entry (2).");
661             }
662 
663             // Then delete them again.
664             for count in 0..actual_entry_count {
665                 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
666                     return;
667                 }
668                 let alias = format!("test_alias_{}", count);
669                 db.remove(2, &alias).expect("Remove Failed (2).");
670             }
671         });
672 
673         // And start deleting the first set of entries.
674         let db_path2 = db_path.clone();
675         let handle2 = thread::spawn(move || {
676             let mut db = DB::new(&db_path2).expect("Failed to open database.");
677 
678             for count in 0..actual_entry_count {
679                 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
680                     return;
681                 }
682                 let alias = format!("test_alias_{}", count);
683                 db.remove(1, &alias).expect("Remove Failed (1)).");
684             }
685         });
686 
687         // While a lot of inserting and deleting is going on we have to open database connections
688         // successfully and then insert and delete a specific entry.
689         let db_path3 = db_path.clone();
690         let handle3 = thread::spawn(move || {
691             for _count in 0..ENTRY_DB_COUNT {
692                 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
693                     return;
694                 }
695                 let mut db = DB::new(&db_path3).expect("Failed to open database.");
696 
697                 db.put(3, &TEST_ALIAS, TEST_BLOB3).expect("Failed to add entry (3).");
698 
699                 db.remove(3, &TEST_ALIAS).expect("Remove failed (3).");
700             }
701         });
702 
703         // While thread 3 is inserting and deleting TEST_ALIAS, we try to get the alias.
704         // This may yield an entry or none, but it must not fail.
705         let handle4 = thread::spawn(move || {
706             for _count in 0..ENTRY_DB_COUNT {
707                 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
708                     return;
709                 }
710                 let mut db = DB::new(&db_path).expect("Failed to open database.");
711 
712                 // This may return Some or None but it must not fail.
713                 db.get(3, &TEST_ALIAS).expect("Failed to get entry (4).");
714             }
715         });
716 
717         handle1.join().expect("Thread 1 panicked.");
718         handle2.join().expect("Thread 2 panicked.");
719         handle3.join().expect("Thread 3 panicked.");
720         handle4.join().expect("Thread 4 panicked.");
721 
722         Ok(())
723     }
724 }
725