blob: 13a914333250cf1d44319cbbab0dfc02df11b216 [file] [log] [blame]
Janis Danisevskis77d72042021-01-20 15:36:30 -08001// 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
Janis Danisevskis3eb829d2021-06-14 14:18:20 -070015//! Implements the android.security.legacykeystore interface.
Janis Danisevskis77d72042021-01-20 15:36:30 -080016
Janis Danisevskis3eb829d2021-06-14 14:18:20 -070017use 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,
Janis Danisevskis77d72042021-01-20 15:36:30 -080021};
Janis Danisevskis3eb829d2021-06-14 14:18:20 -070022use android_security_legacykeystore::binder::{
Andrew Walbrande45c8b2021-04-13 14:42:38 +000023 BinderFeatures, ExceptionCode, Result as BinderResult, Status as BinderStatus, Strong,
24 ThreadState,
25};
Seth Moorefbe5cf52021-06-09 15:59:00 -070026use anyhow::{Context, Result};
Janis Danisevskis5898d152021-06-15 08:23:46 -070027use keystore2::{
Janis Danisevskisea03cff2021-12-16 08:10:17 -080028 async_task::AsyncTask, error::anyhow_error_to_cstring, legacy_blob::LegacyBlobLoader,
29 maintenance::DeleteListener, maintenance::Domain, utils::watchdog as wd,
Janis Danisevskis5898d152021-06-15 08:23:46 -070030};
Janis Danisevskis77d72042021-01-20 15:36:30 -080031use rusqlite::{
32 params, Connection, OptionalExtension, Transaction, TransactionBehavior, NO_PARAMS,
33};
Janis Danisevskis5898d152021-06-15 08:23:46 -070034use std::sync::Arc;
Janis Danisevskis06891072021-02-11 10:28:17 -080035use std::{
36 collections::HashSet,
37 path::{Path, PathBuf},
38};
Janis Danisevskis77d72042021-01-20 15:36:30 -080039
40struct DB {
41 conn: Connection,
42}
43
44impl DB {
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 };
Janis Danisevskis1be7e182021-04-12 14:31:12 -070049
Janis Danisevskis3eb829d2021-06-14 14:18:20 -070050 db.init_tables().context("Trying to initialize legacy keystore db.")?;
Janis Danisevskis77d72042021-01-20 15:36:30 -080051 Ok(db)
52 }
53
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
81 fn is_locked_error(e: &anyhow::Error) -> bool {
Janis Danisevskis13f09152021-04-19 09:55:15 -070082 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 )
Janis Danisevskis77d72042021-01-20 15:36:30 -080087 }
88
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
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
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700118 fn put(&mut self, caller_uid: u32, alias: &str, entry: &[u8]) -> Result<()> {
Janis Danisevskis77d72042021-01-20 15:36:30 -0800119 self.with_transaction(TransactionBehavior::Immediate, |tx| {
120 tx.execute(
121 "INSERT OR REPLACE INTO profiles (owner, alias, profile) values (?, ?, ?)",
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700122 params![caller_uid, alias, entry,],
Janis Danisevskis77d72042021-01-20 15:36:30 -0800123 )
124 .context("In put: Failed to insert or replace.")?;
125 Ok(())
126 })
127 }
128
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()
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700137 .context("In get: failed loading entry.")
Janis Danisevskis77d72042021-01-20 15:36:30 -0800138 })
139 }
140
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 }
Janis Danisevskis5898d152021-06-15 08:23:46 -0700151
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
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) = ?;",
Joel Galenson81a50f22021-07-29 15:39:10 -0700164 params![rustutils::users::AID_USER_OFFSET, user_id],
Janis Danisevskis5898d152021-06-15 08:23:46 -0700165 )
166 .context("In remove_uid: Failed to delete.")
167 })?;
168 Ok(())
169 }
Janis Danisevskis77d72042021-01-20 15:36:30 -0800170}
171
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700172/// This is the main LegacyKeystore error type, it wraps binder exceptions and the
173/// LegacyKeystore errors.
Janis Danisevskis77d72042021-01-20 15:36:30 -0800174#[derive(Debug, thiserror::Error, PartialEq)]
175pub enum Error {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700176 /// Wraps a LegacyKeystore error code.
Janis Danisevskis77d72042021-01-20 15:36:30 -0800177 #[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
184impl Error {
185 /// Short hand for `Error::Error(ERROR_SYSTEM_ERROR)`
186 pub fn sys() -> Self {
187 Error::Error(ERROR_SYSTEM_ERROR)
188 }
189
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700190 /// Short hand for `Error::Error(ERROR_ENTRY_NOT_FOUND)`
Janis Danisevskis77d72042021-01-20 15:36:30 -0800191 pub fn not_found() -> Self {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700192 Error::Error(ERROR_ENTRY_NOT_FOUND)
193 }
194
195 /// Short hand for `Error::Error(ERROR_PERMISSION_DENIED)`
196 pub fn perm() -> Self {
197 Error::Error(ERROR_PERMISSION_DENIED)
Janis Danisevskis77d72042021-01-20 15:36:30 -0800198 }
199}
200
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700201/// This function should be used by legacykeystore service calls to translate error conditions
Janis Danisevskis77d72042021-01-20 15:36:30 -0800202/// into service specific exceptions.
203///
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700204/// All error conditions get logged by this function, except for ERROR_ENTRY_NOT_FOUND error.
Janis Danisevskis77d72042021-01-20 15:36:30 -0800205///
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).
213fn map_or_log_err<T, U, F>(result: Result<U>, handle_ok: F) -> BinderResult<T>
214where
215 F: FnOnce(U) -> BinderResult<T>,
216{
217 result.map_or_else(
218 |e| {
Janis Danisevskis77d72042021-01-20 15:36:30 -0800219 let root_cause = e.root_cause();
Hasini Gunasinghee1d1bbd2021-04-20 18:13:25 +0000220 let (rc, log_error) = match root_cause.downcast_ref::<Error>() {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700221 // Make the entry not found errors silent.
222 Some(Error::Error(ERROR_ENTRY_NOT_FOUND)) => (ERROR_ENTRY_NOT_FOUND, false),
Hasini Gunasinghee1d1bbd2021-04-20 18:13:25 +0000223 Some(Error::Error(e)) => (*e, true),
224 Some(Error::Binder(_, _)) | None => (ERROR_SYSTEM_ERROR, true),
Janis Danisevskis77d72042021-01-20 15:36:30 -0800225 };
Hasini Gunasinghee1d1bbd2021-04-20 18:13:25 +0000226 if log_error {
227 log::error!("{:?}", e);
228 }
Janis Danisevskisea03cff2021-12-16 08:10:17 -0800229 Err(BinderStatus::new_service_specific_error(
230 rc,
231 anyhow_error_to_cstring(&e).as_deref(),
232 ))
Janis Danisevskis77d72042021-01-20 15:36:30 -0800233 },
234 handle_ok,
235 )
236}
237
Janis Danisevskis5898d152021-06-15 08:23:46 -0700238struct LegacyKeystoreDeleteListener {
239 legacy_keystore: Arc<LegacyKeystore>,
240}
241
242impl DeleteListener for LegacyKeystoreDeleteListener {
243 fn delete_namespace(&self, domain: Domain, namespace: i64) -> Result<()> {
244 self.legacy_keystore.delete_namespace(domain, namespace)
245 }
246 fn delete_user(&self, user_id: u32) -> Result<()> {
247 self.legacy_keystore.delete_user(user_id)
248 }
249}
250
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700251/// Implements ILegacyKeystore AIDL interface.
252pub struct LegacyKeystore {
Janis Danisevskis77d72042021-01-20 15:36:30 -0800253 db_path: PathBuf,
Janis Danisevskis06891072021-02-11 10:28:17 -0800254 async_task: AsyncTask,
255}
256
257struct AsyncState {
258 recently_imported: HashSet<(u32, String)>,
259 legacy_loader: LegacyBlobLoader,
260 db_path: PathBuf,
Janis Danisevskis77d72042021-01-20 15:36:30 -0800261}
262
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700263impl LegacyKeystore {
264 /// Note: The filename was chosen before the purpose of this module was extended.
265 /// It is kept for backward compatibility with early adopters.
266 const LEGACY_KEYSTORE_FILE_NAME: &'static str = "vpnprofilestore.sqlite";
267
Janis Danisevskis5898d152021-06-15 08:23:46 -0700268 const WIFI_NAMESPACE: i64 = 102;
269 const AID_WIFI: u32 = 1010;
270
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700271 /// Creates a new LegacyKeystore instance.
Janis Danisevskis5898d152021-06-15 08:23:46 -0700272 pub fn new_native_binder(
273 path: &Path,
274 ) -> (Box<dyn DeleteListener + Send + Sync + 'static>, Strong<dyn ILegacyKeystore>) {
Janis Danisevskis77d72042021-01-20 15:36:30 -0800275 let mut db_path = path.to_path_buf();
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700276 db_path.push(Self::LEGACY_KEYSTORE_FILE_NAME);
Janis Danisevskis06891072021-02-11 10:28:17 -0800277
Janis Danisevskis5898d152021-06-15 08:23:46 -0700278 let legacy_keystore = Arc::new(Self { db_path, async_task: Default::default() });
279 legacy_keystore.init_shelf(path);
280 let service = LegacyKeystoreService { legacy_keystore: legacy_keystore.clone() };
281 (
282 Box::new(LegacyKeystoreDeleteListener { legacy_keystore }),
283 BnLegacyKeystore::new_binder(service, BinderFeatures::default()),
284 )
Janis Danisevskis77d72042021-01-20 15:36:30 -0800285 }
286
287 fn open_db(&self) -> Result<DB> {
288 DB::new(&self.db_path).context("In open_db: Failed to open db.")
289 }
290
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700291 fn get_effective_uid(uid: i32) -> Result<u32> {
292 const AID_SYSTEM: u32 = 1000;
Janis Danisevskis77d72042021-01-20 15:36:30 -0800293 let calling_uid = ThreadState::get_calling_uid();
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700294 let uid = uid as u32;
Janis Danisevskis06891072021-02-11 10:28:17 -0800295
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700296 if uid == UID_SELF as u32 || uid == calling_uid {
297 Ok(calling_uid)
Janis Danisevskis5898d152021-06-15 08:23:46 -0700298 } else if calling_uid == AID_SYSTEM && uid == Self::AID_WIFI {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700299 // The only exception for legacy reasons is allowing SYSTEM to access
300 // the WIFI namespace.
301 // IMPORTANT: If you attempt to add more exceptions, it means you are adding
302 // more callers to this deprecated feature. DON'T!
Janis Danisevskis5898d152021-06-15 08:23:46 -0700303 Ok(Self::AID_WIFI)
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700304 } else {
305 Err(Error::perm()).with_context(|| {
306 format!("In get_effective_uid: caller: {}, requested uid: {}.", calling_uid, uid)
307 })
Janis Danisevskis06891072021-02-11 10:28:17 -0800308 }
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700309 }
310
311 fn get(&self, alias: &str, uid: i32) -> Result<Vec<u8>> {
312 let mut db = self.open_db().context("In get.")?;
313 let uid = Self::get_effective_uid(uid).context("In get.")?;
314
315 if let Some(entry) = db.get(uid, alias).context("In get: Trying to load entry from DB.")? {
316 return Ok(entry);
317 }
318 if self.get_legacy(uid, alias).context("In get: Trying to migrate legacy blob.")? {
Janis Danisevskis06891072021-02-11 10:28:17 -0800319 // If we were able to migrate a legacy blob try again.
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700320 if let Some(entry) =
321 db.get(uid, alias).context("In get: Trying to load entry from DB.")?
Janis Danisevskis06891072021-02-11 10:28:17 -0800322 {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700323 return Ok(entry);
Janis Danisevskis06891072021-02-11 10:28:17 -0800324 }
325 }
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700326 Err(Error::not_found()).context("In get: No such entry.")
Janis Danisevskis77d72042021-01-20 15:36:30 -0800327 }
328
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700329 fn put(&self, alias: &str, uid: i32, entry: &[u8]) -> Result<()> {
330 let uid = Self::get_effective_uid(uid).context("In put.")?;
331 // In order to make sure that we don't have stale legacy entries, make sure they are
Janis Danisevskis06891072021-02-11 10:28:17 -0800332 // migrated before replacing them.
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700333 let _ = self.get_legacy(uid, alias);
Janis Danisevskis06891072021-02-11 10:28:17 -0800334 let mut db = self.open_db().context("In put.")?;
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700335 db.put(uid, alias, entry).context("In put: Trying to insert entry into DB.")
Janis Danisevskis77d72042021-01-20 15:36:30 -0800336 }
337
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700338 fn remove(&self, alias: &str, uid: i32) -> Result<()> {
339 let uid = Self::get_effective_uid(uid).context("In remove.")?;
Janis Danisevskis06891072021-02-11 10:28:17 -0800340 let mut db = self.open_db().context("In remove.")?;
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700341 // In order to make sure that we don't have stale legacy entries, make sure they are
Janis Danisevskis06891072021-02-11 10:28:17 -0800342 // migrated before removing them.
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700343 let _ = self.get_legacy(uid, alias);
344 let removed =
345 db.remove(uid, alias).context("In remove: Trying to remove entry from DB.")?;
Janis Danisevskis77d72042021-01-20 15:36:30 -0800346 if removed {
347 Ok(())
348 } else {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700349 Err(Error::not_found()).context("In remove: No such entry.")
Janis Danisevskis77d72042021-01-20 15:36:30 -0800350 }
351 }
352
Janis Danisevskis5898d152021-06-15 08:23:46 -0700353 fn delete_namespace(&self, domain: Domain, namespace: i64) -> Result<()> {
354 let uid = match domain {
355 Domain::APP => namespace as u32,
356 Domain::SELINUX => {
357 if namespace == Self::WIFI_NAMESPACE {
358 // Namespace WIFI gets mapped to AID_WIFI.
359 Self::AID_WIFI
360 } else {
361 // Nothing to do for any other namespace.
362 return Ok(());
363 }
364 }
365 _ => return Ok(()),
366 };
367
368 if let Err(e) = self.bulk_delete_uid(uid) {
369 log::warn!("In LegacyKeystore::delete_namespace: {:?}", e);
370 }
371 let mut db = self.open_db().context("In LegacyKeystore::delete_namespace.")?;
372 db.remove_uid(uid).context("In LegacyKeystore::delete_namespace.")
373 }
374
375 fn delete_user(&self, user_id: u32) -> Result<()> {
376 if let Err(e) = self.bulk_delete_user(user_id) {
377 log::warn!("In LegacyKeystore::delete_user: {:?}", e);
378 }
379 let mut db = self.open_db().context("In LegacyKeystore::delete_user.")?;
380 db.remove_user(user_id).context("In LegacyKeystore::delete_user.")
381 }
382
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700383 fn list(&self, prefix: &str, uid: i32) -> Result<Vec<String>> {
Janis Danisevskis77d72042021-01-20 15:36:30 -0800384 let mut db = self.open_db().context("In list.")?;
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700385 let uid = Self::get_effective_uid(uid).context("In list.")?;
386 let mut result = self.list_legacy(uid).context("In list.")?;
387 result.append(&mut db.list(uid).context("In list: Trying to get list of entries.")?);
Janis Danisevskis06891072021-02-11 10:28:17 -0800388 result = result.into_iter().filter(|s| s.starts_with(prefix)).collect();
389 result.sort_unstable();
390 result.dedup();
391 Ok(result)
392 }
393
394 fn init_shelf(&self, path: &Path) {
395 let mut db_path = path.to_path_buf();
396 self.async_task.queue_hi(move |shelf| {
397 let legacy_loader = LegacyBlobLoader::new(&db_path);
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700398 db_path.push(Self::LEGACY_KEYSTORE_FILE_NAME);
Janis Danisevskis06891072021-02-11 10:28:17 -0800399
400 shelf.put(AsyncState { legacy_loader, db_path, recently_imported: Default::default() });
401 })
402 }
403
404 fn do_serialized<F, T: Send + 'static>(&self, f: F) -> Result<T>
405 where
406 F: FnOnce(&mut AsyncState) -> Result<T> + Send + 'static,
407 {
408 let (sender, receiver) = std::sync::mpsc::channel::<Result<T>>();
409 self.async_task.queue_hi(move |shelf| {
410 let state = shelf.get_downcast_mut::<AsyncState>().expect("Failed to get shelf.");
411 sender.send(f(state)).expect("Failed to send result.");
412 });
413 receiver.recv().context("In do_serialized: Failed to receive result.")?
414 }
415
416 fn list_legacy(&self, uid: u32) -> Result<Vec<String>> {
417 self.do_serialized(move |state| {
418 state
419 .legacy_loader
Janis Danisevskis5898d152021-06-15 08:23:46 -0700420 .list_legacy_keystore_entries_for_uid(uid)
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700421 .context("Trying to list legacy keystore entries.")
Janis Danisevskis06891072021-02-11 10:28:17 -0800422 })
423 .context("In list_legacy.")
424 }
425
426 fn get_legacy(&self, uid: u32, alias: &str) -> Result<bool> {
427 let alias = alias.to_string();
428 self.do_serialized(move |state| {
429 if state.recently_imported.contains(&(uid, alias.clone())) {
430 return Ok(true);
431 }
432 let mut db = DB::new(&state.db_path).context("In open_db: Failed to open db.")?;
433 let migrated =
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700434 Self::migrate_one_legacy_entry(uid, &alias, &state.legacy_loader, &mut db)
435 .context("Trying to migrate legacy keystore entries.")?;
Janis Danisevskis06891072021-02-11 10:28:17 -0800436 if migrated {
437 state.recently_imported.insert((uid, alias));
438 }
439 Ok(migrated)
440 })
441 .context("In get_legacy.")
442 }
443
Janis Danisevskis5898d152021-06-15 08:23:46 -0700444 fn bulk_delete_uid(&self, uid: u32) -> Result<()> {
445 self.do_serialized(move |state| {
446 let entries = state
447 .legacy_loader
448 .list_legacy_keystore_entries_for_uid(uid)
449 .context("In bulk_delete_uid: Trying to list entries.")?;
450 for alias in entries.iter() {
451 if let Err(e) = state.legacy_loader.remove_legacy_keystore_entry(uid, alias) {
452 log::warn!("In bulk_delete_uid: Failed to delete legacy entry. {:?}", e);
453 }
454 }
455 Ok(())
456 })
457 }
458
459 fn bulk_delete_user(&self, user_id: u32) -> Result<()> {
460 self.do_serialized(move |state| {
461 let entries = state
462 .legacy_loader
463 .list_legacy_keystore_entries_for_user(user_id)
464 .context("In bulk_delete_user: Trying to list entries.")?;
465 for (uid, entries) in entries.iter() {
466 for alias in entries.iter() {
467 if let Err(e) = state.legacy_loader.remove_legacy_keystore_entry(*uid, alias) {
468 log::warn!("In bulk_delete_user: Failed to delete legacy entry. {:?}", e);
469 }
470 }
471 }
472 Ok(())
473 })
474 }
475
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700476 fn migrate_one_legacy_entry(
Janis Danisevskis06891072021-02-11 10:28:17 -0800477 uid: u32,
478 alias: &str,
479 legacy_loader: &LegacyBlobLoader,
480 db: &mut DB,
481 ) -> Result<bool> {
482 let blob = legacy_loader
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700483 .read_legacy_keystore_entry(uid, alias)
484 .context("In migrate_one_legacy_entry: Trying to read legacy keystore entry.")?;
485 if let Some(entry) = blob {
486 db.put(uid, alias, &entry)
487 .context("In migrate_one_legacy_entry: Trying to insert entry into DB.")?;
Janis Danisevskis06891072021-02-11 10:28:17 -0800488 legacy_loader
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700489 .remove_legacy_keystore_entry(uid, alias)
490 .context("In migrate_one_legacy_entry: Trying to delete legacy keystore entry.")?;
Janis Danisevskis06891072021-02-11 10:28:17 -0800491 Ok(true)
492 } else {
493 Ok(false)
494 }
Janis Danisevskis77d72042021-01-20 15:36:30 -0800495 }
496}
497
Janis Danisevskis5898d152021-06-15 08:23:46 -0700498struct LegacyKeystoreService {
499 legacy_keystore: Arc<LegacyKeystore>,
500}
Janis Danisevskis77d72042021-01-20 15:36:30 -0800501
Janis Danisevskis5898d152021-06-15 08:23:46 -0700502impl binder::Interface for LegacyKeystoreService {}
503
504impl ILegacyKeystore for LegacyKeystoreService {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700505 fn get(&self, alias: &str, uid: i32) -> BinderResult<Vec<u8>> {
506 let _wp = wd::watch_millis("ILegacyKeystore::get", 500);
Janis Danisevskis5898d152021-06-15 08:23:46 -0700507 map_or_log_err(self.legacy_keystore.get(alias, uid), Ok)
Janis Danisevskis77d72042021-01-20 15:36:30 -0800508 }
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700509 fn put(&self, alias: &str, uid: i32, entry: &[u8]) -> BinderResult<()> {
510 let _wp = wd::watch_millis("ILegacyKeystore::put", 500);
Janis Danisevskis5898d152021-06-15 08:23:46 -0700511 map_or_log_err(self.legacy_keystore.put(alias, uid, entry), Ok)
Janis Danisevskis77d72042021-01-20 15:36:30 -0800512 }
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700513 fn remove(&self, alias: &str, uid: i32) -> BinderResult<()> {
514 let _wp = wd::watch_millis("ILegacyKeystore::remove", 500);
Janis Danisevskis5898d152021-06-15 08:23:46 -0700515 map_or_log_err(self.legacy_keystore.remove(alias, uid), Ok)
Janis Danisevskis77d72042021-01-20 15:36:30 -0800516 }
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700517 fn list(&self, prefix: &str, uid: i32) -> BinderResult<Vec<String>> {
518 let _wp = wd::watch_millis("ILegacyKeystore::list", 500);
Janis Danisevskis5898d152021-06-15 08:23:46 -0700519 map_or_log_err(self.legacy_keystore.list(prefix, uid), Ok)
Janis Danisevskis77d72042021-01-20 15:36:30 -0800520 }
521}
522
523#[cfg(test)]
524mod db_test {
525 use super::*;
526 use keystore2_test_utils::TempDir;
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700527 use std::sync::Arc;
528 use std::thread;
529 use std::time::Duration;
530 use std::time::Instant;
Janis Danisevskis77d72042021-01-20 15:36:30 -0800531
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700532 static TEST_ALIAS: &str = "test_alias";
Janis Danisevskis77d72042021-01-20 15:36:30 -0800533 static TEST_BLOB1: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
534 static TEST_BLOB2: &[u8] = &[2, 2, 3, 4, 5, 6, 7, 8, 9, 0];
535 static TEST_BLOB3: &[u8] = &[3, 2, 3, 4, 5, 6, 7, 8, 9, 0];
536 static TEST_BLOB4: &[u8] = &[3, 2, 3, 4, 5, 6, 7, 8, 9, 0];
537
538 #[test]
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700539 fn test_entry_db() {
540 let test_dir = TempDir::new("entrydb_test_").expect("Failed to create temp dir.");
541 let mut db = DB::new(&test_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME))
542 .expect("Failed to open database.");
Janis Danisevskis77d72042021-01-20 15:36:30 -0800543
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700544 // Insert three entries for owner 2.
Janis Danisevskis77d72042021-01-20 15:36:30 -0800545 db.put(2, "test1", TEST_BLOB1).expect("Failed to insert test1.");
546 db.put(2, "test2", TEST_BLOB2).expect("Failed to insert test2.");
547 db.put(2, "test3", TEST_BLOB3).expect("Failed to insert test3.");
548
549 // Check list returns all inserted aliases.
550 assert_eq!(
551 vec!["test1".to_string(), "test2".to_string(), "test3".to_string(),],
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700552 db.list(2).expect("Failed to list entries.")
Janis Danisevskis77d72042021-01-20 15:36:30 -0800553 );
554
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700555 // There should be no entries for owner 1.
556 assert_eq!(Vec::<String>::new(), db.list(1).expect("Failed to list entries."));
Janis Danisevskis77d72042021-01-20 15:36:30 -0800557
558 // Check the content of the three entries.
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700559 assert_eq!(Some(TEST_BLOB1), db.get(2, "test1").expect("Failed to get entry.").as_deref());
560 assert_eq!(Some(TEST_BLOB2), db.get(2, "test2").expect("Failed to get entry.").as_deref());
561 assert_eq!(Some(TEST_BLOB3), db.get(2, "test3").expect("Failed to get entry.").as_deref());
Janis Danisevskis77d72042021-01-20 15:36:30 -0800562
563 // Remove test2 and check and check that it is no longer retrievable.
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700564 assert!(db.remove(2, "test2").expect("Failed to remove entry."));
565 assert!(db.get(2, "test2").expect("Failed to get entry.").is_none());
Janis Danisevskis77d72042021-01-20 15:36:30 -0800566
567 // test2 should now no longer be in the list.
568 assert_eq!(
569 vec!["test1".to_string(), "test3".to_string(),],
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700570 db.list(2).expect("Failed to list entries.")
Janis Danisevskis77d72042021-01-20 15:36:30 -0800571 );
572
573 // Put on existing alias replaces it.
574 // Verify test1 is TEST_BLOB1.
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700575 assert_eq!(Some(TEST_BLOB1), db.get(2, "test1").expect("Failed to get entry.").as_deref());
Janis Danisevskis77d72042021-01-20 15:36:30 -0800576 db.put(2, "test1", TEST_BLOB4).expect("Failed to replace test1.");
577 // Verify test1 is TEST_BLOB4.
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700578 assert_eq!(Some(TEST_BLOB4), db.get(2, "test1").expect("Failed to get entry.").as_deref());
Janis Danisevskis77d72042021-01-20 15:36:30 -0800579 }
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700580
581 #[test]
Janis Danisevskis5898d152021-06-15 08:23:46 -0700582 fn test_delete_uid() {
583 let test_dir = TempDir::new("test_delete_uid_").expect("Failed to create temp dir.");
584 let mut db = DB::new(&test_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME))
585 .expect("Failed to open database.");
586
587 // Insert three entries for owner 2.
588 db.put(2, "test1", TEST_BLOB1).expect("Failed to insert test1.");
589 db.put(2, "test2", TEST_BLOB2).expect("Failed to insert test2.");
590 db.put(3, "test3", TEST_BLOB3).expect("Failed to insert test3.");
591
592 db.remove_uid(2).expect("Failed to remove uid 2");
593
594 assert_eq!(Vec::<String>::new(), db.list(2).expect("Failed to list entries."));
595
596 assert_eq!(vec!["test3".to_string(),], db.list(3).expect("Failed to list entries."));
597 }
598
599 #[test]
600 fn test_delete_user() {
601 let test_dir = TempDir::new("test_delete_user_").expect("Failed to create temp dir.");
602 let mut db = DB::new(&test_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME))
603 .expect("Failed to open database.");
604
605 // Insert three entries for owner 2.
Joel Galenson81a50f22021-07-29 15:39:10 -0700606 db.put(2 + 2 * rustutils::users::AID_USER_OFFSET, "test1", TEST_BLOB1)
Janis Danisevskis5898d152021-06-15 08:23:46 -0700607 .expect("Failed to insert test1.");
Joel Galenson81a50f22021-07-29 15:39:10 -0700608 db.put(4 + 2 * rustutils::users::AID_USER_OFFSET, "test2", TEST_BLOB2)
Janis Danisevskis5898d152021-06-15 08:23:46 -0700609 .expect("Failed to insert test2.");
610 db.put(3, "test3", TEST_BLOB3).expect("Failed to insert test3.");
611
612 db.remove_user(2).expect("Failed to remove user 2");
613
614 assert_eq!(
615 Vec::<String>::new(),
Joel Galenson81a50f22021-07-29 15:39:10 -0700616 db.list(2 + 2 * rustutils::users::AID_USER_OFFSET).expect("Failed to list entries.")
Janis Danisevskis5898d152021-06-15 08:23:46 -0700617 );
618
619 assert_eq!(
620 Vec::<String>::new(),
Joel Galenson81a50f22021-07-29 15:39:10 -0700621 db.list(4 + 2 * rustutils::users::AID_USER_OFFSET).expect("Failed to list entries.")
Janis Danisevskis5898d152021-06-15 08:23:46 -0700622 );
623
624 assert_eq!(vec!["test3".to_string(),], db.list(3).expect("Failed to list entries."));
625 }
626
627 #[test]
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700628 fn concurrent_legacy_keystore_entry_test() -> Result<()> {
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700629 let temp_dir = Arc::new(
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700630 TempDir::new("concurrent_legacy_keystore_entry_test_")
631 .expect("Failed to create temp dir."),
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700632 );
633
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700634 let db_path = temp_dir.build().push(LegacyKeystore::LEGACY_KEYSTORE_FILE_NAME).to_owned();
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700635
636 let test_begin = Instant::now();
637
638 let mut db = DB::new(&db_path).expect("Failed to open database.");
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700639 const ENTRY_COUNT: u32 = 5000u32;
640 const ENTRY_DB_COUNT: u32 = 5000u32;
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700641
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700642 let mut actual_entry_count = ENTRY_COUNT;
643 // First insert ENTRY_COUNT entries.
644 for count in 0..ENTRY_COUNT {
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700645 if Instant::now().duration_since(test_begin) >= Duration::from_secs(15) {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700646 actual_entry_count = count;
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700647 break;
648 }
649 let alias = format!("test_alias_{}", count);
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700650 db.put(1, &alias, TEST_BLOB1).expect("Failed to add entry (1).");
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700651 }
652
653 // Insert more keys from a different thread and into a different namespace.
654 let db_path1 = db_path.clone();
655 let handle1 = thread::spawn(move || {
656 let mut db = DB::new(&db_path1).expect("Failed to open database.");
657
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700658 for count in 0..actual_entry_count {
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700659 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
660 return;
661 }
662 let alias = format!("test_alias_{}", count);
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700663 db.put(2, &alias, TEST_BLOB2).expect("Failed to add entry (2).");
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700664 }
665
666 // Then delete them again.
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700667 for count in 0..actual_entry_count {
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700668 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
669 return;
670 }
671 let alias = format!("test_alias_{}", count);
672 db.remove(2, &alias).expect("Remove Failed (2).");
673 }
674 });
675
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700676 // And start deleting the first set of entries.
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700677 let db_path2 = db_path.clone();
678 let handle2 = thread::spawn(move || {
679 let mut db = DB::new(&db_path2).expect("Failed to open database.");
680
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700681 for count in 0..actual_entry_count {
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700682 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
683 return;
684 }
685 let alias = format!("test_alias_{}", count);
686 db.remove(1, &alias).expect("Remove Failed (1)).");
687 }
688 });
689
690 // While a lot of inserting and deleting is going on we have to open database connections
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700691 // successfully and then insert and delete a specific entry.
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700692 let db_path3 = db_path.clone();
693 let handle3 = thread::spawn(move || {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700694 for _count in 0..ENTRY_DB_COUNT {
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700695 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
696 return;
697 }
698 let mut db = DB::new(&db_path3).expect("Failed to open database.");
699
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700700 db.put(3, TEST_ALIAS, TEST_BLOB3).expect("Failed to add entry (3).");
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700701
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700702 db.remove(3, TEST_ALIAS).expect("Remove failed (3).");
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700703 }
704 });
705
706 // While thread 3 is inserting and deleting TEST_ALIAS, we try to get the alias.
707 // This may yield an entry or none, but it must not fail.
708 let handle4 = thread::spawn(move || {
Janis Danisevskis3eb829d2021-06-14 14:18:20 -0700709 for _count in 0..ENTRY_DB_COUNT {
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700710 if Instant::now().duration_since(test_begin) >= Duration::from_secs(40) {
711 return;
712 }
713 let mut db = DB::new(&db_path).expect("Failed to open database.");
714
715 // This may return Some or None but it must not fail.
Chris Wailesd5aaaef2021-07-27 16:04:33 -0700716 db.get(3, TEST_ALIAS).expect("Failed to get entry (4).");
Janis Danisevskis1be7e182021-04-12 14:31:12 -0700717 }
718 });
719
720 handle1.join().expect("Thread 1 panicked.");
721 handle2.join().expect("Thread 2 panicked.");
722 handle3.join().expect("Thread 3 panicked.");
723 handle4.join().expect("Thread 4 panicked.");
724
725 Ok(())
726 }
Janis Danisevskis77d72042021-01-20 15:36:30 -0800727}