Cache the KeystoreKeyBackend with a lazy static.
This patch makes KeystoreKeyBackend Sync and uses a lazy static to cache
the back end in the permissions module.
Test: atest keystore2_test
Bug: 159466840
Change-Id: Ibc7851baede3506acbdf962e59c281fa16cfaf0e
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index a48396a..154b675 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -21,6 +21,7 @@
"libanyhow",
"libkeystore_aidl_generated",
"libkeystore2_selinux",
+ "liblazy_static",
"liblibsqlite3_sys",
"liblog_rust",
"librand",
@@ -40,6 +41,7 @@
"libanyhow",
"libkeystore_aidl_generated",
"libkeystore2_selinux",
+ "liblazy_static",
"liblibsqlite3_sys",
"liblog_rust",
"librusqlite",
diff --git a/keystore2/selinux/src/lib.rs b/keystore2/selinux/src/lib.rs
index 30a235a..05f9db8 100644
--- a/keystore2/selinux/src/lib.rs
+++ b/keystore2/selinux/src/lib.rs
@@ -25,6 +25,7 @@
use std::ffi::{CStr, CString};
use std::fmt;
use std::io;
+use std::marker::{Send, Sync};
pub use std::ops::Deref;
use std::os::raw::c_char;
use std::ptr;
@@ -141,6 +142,10 @@
handle: *mut selinux::selabel_handle,
}
+// KeystoreKeyBackend is Sync because selabel_lookup is thread safe.
+unsafe impl Sync for KeystoreKeyBackend {}
+unsafe impl Send for KeystoreKeyBackend {}
+
impl KeystoreKeyBackend {
const BACKEND_TYPE: i32 = SELABEL_CTX_ANDROID_KEYSTORE2_KEY as i32;
@@ -164,6 +169,9 @@
}
}
+// Because KeystoreKeyBackend is Sync and Send, member function must never call
+// non thread safe libselinux functions. As of this writing no non thread safe
+// functions exist that could be called on a label backend handle.
impl Backend for KeystoreKeyBackend {
fn lookup(&self, key: &str) -> Result<Context> {
let mut con: *mut c_char = ptr::null_mut();
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index a5a63ee..0db56dd 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -30,12 +30,25 @@
use selinux::Backend;
+use lazy_static::lazy_static;
+
// Replace getcon with a mock in the test situation
#[cfg(not(test))]
use selinux::getcon;
#[cfg(test)]
use tests::test_getcon as getcon;
+lazy_static! {
+ // Panicking here is allowed because keystore cannot function without this backend
+ // and it would happen early and indicate a gross misconfiguration of the device.
+ static ref KEYSTORE2_KEY_LABEL_BACKEND: selinux::KeystoreKeyBackend =
+ selinux::KeystoreKeyBackend::new().unwrap();
+}
+
+fn lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context> {
+ KEYSTORE2_KEY_LABEL_BACKEND.lookup(&namespace.to_string())
+}
+
/// The below example wraps the enum MyPermission in the tuple struct `MyPerm` and implements
/// * `From<i32> for `MyPerm`, where each unknown numeric value is mapped to the given default,
/// here `None`
@@ -369,20 +382,11 @@
key: &aidl::KeyDescriptor,
) -> anyhow::Result<()> {
use aidl::Domain;
- use selinux::KeystoreKeyBackend;
let target_context = match key.domain {
Domain::App => getcon().context("check_grant_permission: getcon failed.")?,
- Domain::SELinux => {
- // TODO cache an open backend, possible use a lazy static.
- let backend = KeystoreKeyBackend::new().context(concat!(
- "check_grant_permission: Domain::SELinux: ",
- "Failed to create selinux keystore backend."
- ))?;
- backend
- .lookup(format!("{}", key.namespace_).as_str())
- .context("check_grant_permission: Domain::SELinux: Failed to lookup namespace")?
- }
+ Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
+ .context("check_grant_permission: Domain::SELinux: Failed to lookup namespace.")?,
_ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
};
@@ -429,20 +433,12 @@
access_vector: &Option<KeyPermSet>,
) -> anyhow::Result<()> {
use aidl::Domain;
- use selinux::KeystoreKeyBackend;
let target_context = match key.domain {
// apps get the default keystore context
Domain::App => getcon().context("check_key_permission: getcon failed.")?,
- Domain::SELinux => {
- // TODO cache an open backend, possible use a lasy static.
- let backend = KeystoreKeyBackend::new().context(
- "check_key_permission: Domain::SELinux: Failed to create selinux keystore backend.",
- )?;
- backend
- .lookup(format!("{}", key.namespace_).as_str())
- .context("check_key_permission: Domain::SELinux: Failed to lookup namespace")?
- }
+ Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
+ .context("check_key_permission: Domain::SELinux: Failed to lookup namespace.")?,
Domain::Grant => {
match access_vector {
Some(pv) => {
@@ -468,10 +464,7 @@
return Err(KsError::sys()).context("Cannot check permission for Domain::KeyId.");
}
Domain::Blob => {
- let backend = KeystoreKeyBackend::new()
- .context("Domain::Blob: Failed to create selinux keystore backend.")?;
- let tctx = backend
- .lookup(format!("{}", key.namespace_).as_str())
+ let tctx = lookup_keystore2_key_context(key.namespace_)
.context("Domain::Blob: Failed to lookup namespace.")?;
// If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
// permission in addition to the requested permission.