Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix keymanager to be thread-safe #92

Merged
merged 2 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions modules/enclave-api/src/enclave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ use store::host::{HostStore, IntoCommitStore};
use store::transaction::{CommitStore, CreatedTx, UpdateKey};

/// `Enclave` keeps an enclave id and reference to the host environement
pub struct Enclave<S> {
pub struct Enclave<S: CommitStore> {
pub(crate) path: PathBuf,
pub(crate) key_manager: EnclaveKeyManager,
pub(crate) store: Arc<RwLock<HostStore>>,
pub(crate) sgx_enclave: SgxEnclave,
_marker: PhantomData<S>,
}

impl<S> Enclave<S> {
impl<S: CommitStore> Enclave<S> {
pub fn new(
path: impl Into<PathBuf>,
key_manager: EnclaveKeyManager,
Expand Down Expand Up @@ -49,7 +49,7 @@ impl<S> Enclave<S> {
}

/// `EnclaveInfo` is an accessor to enclave information
pub trait EnclaveInfo {
pub trait EnclaveInfo: Sync + Send {
/// `get_eid` returns the enclave id
fn get_eid(&self) -> sgx_enclave_id_t;
/// `metadata` returns the metadata of the enclave
Expand All @@ -58,7 +58,7 @@ pub trait EnclaveInfo {
fn get_key_manager(&self) -> &EnclaveKeyManager;
}

impl<S> EnclaveInfo for Enclave<S> {
impl<S: CommitStore> EnclaveInfo for Enclave<S> {
/// `get_eid` returns the enclave id
fn get_eid(&self) -> sgx_enclave_id_t {
self.sgx_enclave.geteid()
Expand Down
10 changes: 9 additions & 1 deletion modules/keymanager/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ define_error! {

Rusqlite
[TraceError<rusqlite::Error>]
|_| { "rusqlite error" }
|_| { "rusqlite error" },

MutexLock
{
descr: String
}
|e| {
format_args!("mutex lock error: descr={}", e.descr)
}
}
}

Expand Down
57 changes: 42 additions & 15 deletions modules/keymanager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,42 @@ use lcp_types::{Mrenclave, Time};
use log::*;
use rusqlite::{params, types::Type, Connection};
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
use std::{ops::Deref, path::Path, time::Duration};

pub static KEY_MANAGER_DB: &str = "km.sqlite";

pub struct EnclaveKeyManager {
conn: Connection,
conn: Mutex<Connection>,
}

impl EnclaveKeyManager {
pub fn new(home_dir: &Path) -> Result<Self, Error> {
let km_db = home_dir.join(KEY_MANAGER_DB);
let db_exists = km_db.exists();
let conn = Connection::open(&km_db)?;
let conn = Mutex::new(Connection::open(&km_db)?);
let this = Self { conn };
if !db_exists {
this.setup()?;
this.init_db()?;
info!("initialized Key Manager: {:?}", km_db);
}
Ok(this)
}

#[cfg(test)]
pub fn new_in_memory() -> Result<Self, Error> {
let conn = Connection::open_in_memory()?;
let conn = Mutex::new(Connection::open_in_memory()?);
let this = Self { conn };
this.setup()?;
this.init_db()?;
Ok(this)
}

fn setup(&self) -> Result<(), Error> {
self.conn.execute_batch(
fn init_db(&self) -> Result<(), Error> {
let conn = self
.conn
.lock()
.map_err(|e| Error::mutex_lock(e.to_string()))?;
conn.execute_batch(
r#"
BEGIN;
CREATE TABLE enclave_keys (
Expand All @@ -61,7 +66,11 @@ impl EnclaveKeyManager {

/// Load a sealed enclave key by address
pub fn load(&self, address: Address) -> Result<SealedEnclaveKeyInfo, Error> {
let mut stmt = self.conn.prepare(
let conn = self
.conn
.lock()
.map_err(|e| Error::mutex_lock(e.to_string()))?;
let mut stmt = conn.prepare(
"SELECT ek_sealed, mrenclave, avr, signature, signing_cert FROM enclave_keys WHERE ek_address = ?1",
)?;
let key_info = stmt.query_row(params![address.to_hex_string()], |row| {
Expand Down Expand Up @@ -98,7 +107,11 @@ impl EnclaveKeyManager {
sealed_ek: SealedEnclaveKey,
mrenclave: Mrenclave,
) -> Result<(), Error> {
let mut stmt = self.conn.prepare(
let conn = self
.conn
.lock()
.map_err(|e| Error::mutex_lock(e.to_string()))?;
let mut stmt = conn.prepare(
"INSERT INTO enclave_keys (ek_address, ek_sealed, mrenclave) VALUES (?1, ?2, ?3)",
)?;
let _ = stmt.execute(params![
Expand All @@ -115,9 +128,13 @@ impl EnclaveKeyManager {
address: Address,
avr: EndorsedAttestationVerificationReport,
) -> Result<(), Error> {
let conn = self
.conn
.lock()
.map_err(|e| Error::mutex_lock(e.to_string()))?;
let attested_at = avr.get_avr()?.attestation_time()?;
// update avr and attested_at and signature and sigining_cert
let mut stmt = self.conn.prepare(
let mut stmt = conn.prepare(
"UPDATE enclave_keys SET avr = ?1, attested_at = ?2, signature = ?3, signing_cert = ?4 WHERE ek_address = ?5",
)?;
stmt.execute(params![
Expand All @@ -132,7 +149,11 @@ impl EnclaveKeyManager {

/// Returns a list of available enclave keys
pub fn available_keys(&self, mrenclave: Mrenclave) -> Result<Vec<SealedEnclaveKeyInfo>, Error> {
let mut stmt = self.conn.prepare(
let conn = self
.conn
.lock()
.map_err(|e| Error::mutex_lock(e.to_string()))?;
let mut stmt = conn.prepare(
r#"
SELECT ek_address, ek_sealed, mrenclave, avr, signature, signing_cert
FROM enclave_keys
Expand Down Expand Up @@ -164,7 +185,11 @@ impl EnclaveKeyManager {

/// Returns a list of all enclave keys
pub fn all_keys(&self) -> Result<Vec<SealedEnclaveKeyInfo>, Error> {
let mut stmt = self.conn.prepare(
let conn = self
.conn
.lock()
.map_err(|e| Error::mutex_lock(e.to_string()))?;
let mut stmt = conn.prepare(
"SELECT ek_address, ek_sealed, mrenclave, avr, signature, signing_cert FROM enclave_keys ORDER BY updated_at DESC",
)?;
let key_infos = stmt
Expand Down Expand Up @@ -200,10 +225,12 @@ impl EnclaveKeyManager {

/// Prune keys after the expiration time(secs) from the attestation time.
pub fn prune(&self, expiration_time: u64) -> Result<usize, Error> {
let expired = (Time::now() - Duration::from_secs(expiration_time))?;
let mut stmt = self
let conn = self
.conn
.prepare("DELETE FROM enclave_keys WHERE attested_at <= ?1")?;
.lock()
.map_err(|e| Error::mutex_lock(e.to_string()))?;
let expired = (Time::now() - Duration::from_secs(expiration_time))?;
let mut stmt = conn.prepare("DELETE FROM enclave_keys WHERE attested_at <= ?1")?;
let count = stmt.execute(params![expired.as_unix_timestamp_secs()])?;
Ok(count)
}
Expand Down
13 changes: 0 additions & 13 deletions modules/service/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,6 @@ where
}
}

unsafe impl<E, S> Send for AppService<E, S>
where
S: CommitStore + 'static,
E: EnclaveProtoAPI<S> + 'static,
{
}
unsafe impl<E, S> Sync for AppService<E, S>
where
S: CommitStore + 'static,
E: EnclaveProtoAPI<S> + 'static,
{
}

impl<E, S> AppService<E, S>
where
S: CommitStore + 'static,
Expand Down
63 changes: 59 additions & 4 deletions modules/store/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,72 @@ use crate::store::TxId;
use crate::transaction::{CommitStore, CreatedTx, Tx, TxAccessor};
use crate::{KVStore, Result};
use std::collections::HashMap;
use std::sync::Mutex;

// MemStore is only available for testing purposes
#[derive(Default, Debug)]
pub struct MemStore {
pub struct MemStore(Mutex<InnerMemStore>);

impl KVStore for MemStore {
fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
self.0.lock().unwrap().get(key)
}

fn set(&mut self, key: Vec<u8>, value: Vec<u8>) {
self.0.lock().unwrap().set(key, value)
}

fn remove(&mut self, key: &[u8]) {
self.0.lock().unwrap().remove(key)
}
}

impl TxAccessor for MemStore {
fn run_in_tx<T>(&self, tx_id: TxId, f: impl FnOnce(&dyn KVStore) -> T) -> Result<T> {
self.0.lock().unwrap().run_in_tx(tx_id, f)
}

fn run_in_mut_tx<T>(
&mut self,
tx_id: TxId,
f: impl FnOnce(&mut dyn KVStore) -> T,
) -> Result<T> {
self.0.lock().unwrap().run_in_mut_tx(tx_id, f)
}
}

impl CommitStore for MemStore {
type Tx = MemTx;

fn create_transaction(
&mut self,
_update_key: Option<crate::transaction::UpdateKey>,
) -> Result<Self::Tx> {
self.0.lock().unwrap().create_transaction(_update_key)
}

fn begin(&mut self, tx: &<Self::Tx as CreatedTx>::PreparedTx) -> Result<()> {
self.0.lock().unwrap().begin(tx)
}

fn commit(&mut self, tx: <Self::Tx as CreatedTx>::PreparedTx) -> Result<()> {
self.0.lock().unwrap().commit(tx)
}

fn rollback(&mut self, tx: <Self::Tx as CreatedTx>::PreparedTx) {
self.0.lock().unwrap().rollback(tx)
}
}

#[derive(Default, Debug)]
pub struct InnerMemStore {
running_tx_exists: bool,
latest_tx_id: TxId,
uncommitted_data: HashMap<Vec<u8>, Option<Vec<u8>>>,
committed_data: HashMap<Vec<u8>, Vec<u8>>,
}

impl KVStore for MemStore {
impl KVStore for InnerMemStore {
fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
if self.running_tx_exists {
match self.uncommitted_data.get(key) {
Expand Down Expand Up @@ -42,7 +97,7 @@ impl KVStore for MemStore {
}
}

impl TxAccessor for MemStore {
impl TxAccessor for InnerMemStore {
fn run_in_tx<T>(&self, _tx_id: TxId, f: impl FnOnce(&dyn KVStore) -> T) -> Result<T> {
Ok(f(self))
}
Expand All @@ -56,7 +111,7 @@ impl TxAccessor for MemStore {
}
}

impl CommitStore for MemStore {
impl CommitStore for InnerMemStore {
type Tx = MemTx;

fn create_transaction(
Expand Down
2 changes: 1 addition & 1 deletion modules/store/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub trait CreatedTx: Tx {
}

/// `CommitStore` is a store that supports transactions
pub trait CommitStore {
pub trait CommitStore: Sync + Send {
type Tx: CreatedTx;

/// `create_transaction` creates a transaction with a given `update_key`
Expand Down
Loading